retrieving data from Mysql table using c# - c#

I'm trying to write a c sharp program where I enter data to database and read data from database
Database name is kangoojump and I have an admin table here to store id,username and password
I created a login screen for my program and want to type in my username& password and when I press the login button I want to retrieve data from the database table and compare the two and if they match give access to next form...
here is my code
MySqlCommand SelectCommand = new MySqlCommand(" SELECT username FROM kangoojump.admin where _id=1", mcon);
MySqlDataReader myReader;
mcon.Open();
myReader = SelectCommand.ExecuteReader();
while (myReader.Read())
{
temp1 = myReader["username"].ToString();
}
I have created a username,password,temp1,temp2 of type string in my function but
when I try to run the program I get the error that " use of unassigned variable 'temp1' "
what is the problem with my code?
Thanks

Where have you defined temp1 ?
when defining temp1
do it as follows -
string temp1 = string.Empty;

The problem has to do (in part) with this line of code:
while (myReader.Read())
You and I are smart enough to know that the database query will always return a row, but the compiler is not. This because we have information that is not available to the compiler: we know there will be an admin record. The compiler can't know this. Therefore, the compiler can't guarantee that your code will ever enter the body of that while loop. This means it also can't guarantee that you will ever assign a value to the temp1 variable... hence, your potentially "unassigned variable 'temp1'": the compiler can't guarantee you've written a reasonable value to the variable yet, and you're not allowed to read from it until you do.
The easy solution is to just assign a basic value to the variable when you first declare it:
string temp1 = "";
And while we're here: never ever ever store plain-text passwords. Store one-way password hashes.

Related

Having trouble plucking the correct value from my DB

Sorry for not putting the question in the title, the real problem is that I can't see an issue with my code but it's not producing what I want it to.
So I've written some code which is meant to take the database's Password field and inspect its value then store that value as a string within a password variable. In SQL Management studio the value is 'MyPass', that's what I'm expecting to get when I print out the password variable as a MessageBox. Instead I get two boxes, 'password' and then 'password123'. The only column within the table: Login, is one called Password.
Here is the using statement:
using(SqlConnection con = new SqlConnection(connectionString))
{
string query = "SELECT Password FROM LoginInfo";
con.Open();
//SqlCommand to be executed against my DB with the query text and the connection object.
SqlCommand myCommand = new SqlCommand(query, con);
//Sends CommandText to connection. Creates a
SqlDataReader read = myCommand.ExecuteReader();
while(read.Read())
{
//Convert read to IDataRecord.
ReadSingleRow((IDataRecord)read);
}
read.Close();
}
I apologize if my comments are incorrect, I wrote them down because they help me think.
You can read my interpretation of the code below and tell me what's wrong with my thinking process or you can just scour the code samples for errors.
My Interpretation (If you'll indulge me):
So, in the using statement we create a connection, a query string, an SqlCommand and an SqlDataReader. Passing the SqlCommand the query string and the connection object we then set its instance equal to an SqlDataReader, named 'read' with the method ExecuteReader() which takes the command text to wherever the connection is through the connection object.
Next we use a while loop, we use the .Read() to advance the reader on to the first record, since my db only has one record 'Password' this just moves it on to that. Within while we have the method ReadSingleRow which converts the reader instance into an IDataRecord: ((IDataRecord)read).
The ReadSingleRow method:
public void ReadSingleRow(IDataRecord record)
{
UserPass = record.GetString(record.GetOrdinal("Password"));
MessageBox.Show(UserPass);
}
the IDataRecord retrieves the string value of the oridinal(ID) password. My understanding is that it looks at the value of Password: Mypass, and then stores that within the UserPass string variable. The MessageBox of course blurts out the variable as a test to see if it worked. It didn't.
So my question is the annoying: why didn't this work? Perhaps I am miss-using the IDataRecord.

C# error : Input string was not in a correct format

I was getting this error: "Input string was not in a correct format."
Here is my Code:
private void UpdatePOdetailBalance(int Qty)
{
int newbal;
SqlCommand com = new SqlCommand();
com.Connection = cn;
newbal = Convert.ToInt16(txtQtyOrdered.Text) - Qty;
com.CommandText =
"UPDATE PODetail SET BalanceQty="+ newbal +" WHERE OrderID=" +
Convert.ToInt16(txtPONumber.Text) + "AND ItemID=" +
Convert.ToInt16(txtItemNo.Text);
com.ExecuteNonQuery();
}
private void btnOK_Click(object sender, EventArgs e)
{
UpdatePOdetailBalance(Convert.ToInt16(txtQuantity.Text));
}
I want to compute the newbal which is equal to txtQtyOrdered minus Qty but i'm getting this error please help me with this. Thanks.
The problem stated by your error message is probably on one of the lines that try to convert the value in the textboxes to a short integer. Without any check, the value typed by your user could be anything but a number and you get this error message (for example, if you user leaves the textboxes empty).
You should try to check if the textboxes content could be converted to a valid short integer using TryParse before attempting to execute the query
int ordered;
if(!int16.TryParse(txtQtyOrdered.Text, out ordered))
{
MessageBox.Show("Invalid number for Ordered quantity");
return;
}
int orderID;
if(!int16.TryParse(txtPONumber.Text, out orderID))
{
MessageBox.Show("Invalid number for OrderId");
return;
}
int itemID;
if(!int16.TryParse(txtItemNo.Text, out itemID))
{
MessageBox.Show("Invalid number for ItemID");
return;
}
At this point you could execute your calculation using the converted short integers and then write your query in this way (adding a space before the AND)
com.CommandText =
"UPDATE PODetail SET BalanceQty="+ newbal.ToString() +
" WHERE OrderID=" + orderID.ToString() +
" AND ItemID=" + itemID.ToString();
But the string concatenation of query text and user input is never advised as a good practice (in your case is harmless because if the conversion is successful you don't have to worry about Sql Injection, but don't take the habit to do it).
So the perfect way to write this query is through the use of a parametrized query
com.CommandText =
"UPDATE PODetail SET BalanceQty=#newbal " +
" WHERE OrderID=#orderID " +
" AND ItemID= #itemID"
com.Parameters.AddWithValue("#newbal", newBal);
com.Parameters.AddWithValue("#orderID", orderID);
com.Parameters.AddWithValue("#itemID", itemID);
com.ExecuteNonQuery();
As a good article on Parameterized query and why to use them, I suggest to read these old words from Jeff Atwood
You need to put a space before your "AND" and that you are trying to convert a string to an integer that isn't an integer.
I'd recommend making changes according to the following code review suggestions based on the code (listed in order of value (cost/benefit of "fixing")):
This method, which is accessing a database should not be reading controls to get its values. Instead there should be an event handler, such as a button click, that parses the values of other controls, using TryParse, as gregjer answered. By segregating the UI and Data code, the data access layer is easier to test and by parsing at the surface (the UI layer) exceptions dealing with bad user input will be caught as soon as possible.
Dynamic SQL via strings in the database or in the data access layer w/i .NET is open to SQL injection. You are resolving that issue by parsing the text, so awesome job by you. BUT, this was already handled by the .NET team by providing parameterized commands. Refer to the MSDN SqlCommand.Parameters or see here for a brief, including how a consuming developer groks this topic: When should "SqlDbType" and "size" be used when adding SqlCommand Parameters?
Variable naming. Instead of Qty, standard .NET naming conventions would call for quantity, camelCased since it is a parameter and the full human language name, not a shorthand or abbreviation, especially for publicly visible bits. IntelliSense makes long variable names not a problem. Since .NET is unwieldy using just Notepad, it should be assumed that other developers are using an IDE such as VisualStudio or SharpDevelop, so use meaningful names.
Stored procedures should be used. Every time this SQL is executed, SQL Server needs to check its command cache minimally, but if the command has been flushed from cache, the SQL command needs to be interpreted and encached (put into cache). This as well as the fact that using a stored procedure requires "shipping" less bytes on every call to the database.
That error means that the string you're trying to convert is not an integer.
Try to use int.TryParse
int newbal;
if(int.TryParse(txtQtyOrdered.Text, out newbal))
newbal = newbal - Qty;
the same with other texts you are trying to convert
... and add space before " AND which will generate next error
I think you need to debug your code. During debugging copy your query from "com.CommandText" and paste in SQL Server you find the error
There is only a query error nothing else...
May be txtQtyOrdered value is not integer, there is also need blank space "AND ItemID=" to " AND ItemID="
Thanks,
Taha
First - You are missing a space before "AND"
You should try to parse the values before the update statement.
You should decide what you want to do in case the input from the textbox wasn't in the correct format rather then just get an exception when you try to update.
This isn't the right way to format strings, You should use string.Format
you can sometimes run into this problem when you have multiple parameters and are using Oracle or DB2 databases. They dont's support named parameters or it's not turned on.
Oracle:
Dim cmd As OracleCommand = DirectCast(connection.CreateCommand, OracleCommand)
cmd.BindByName = True
Make sure you parameters are added to the command object in the same order as the sql statement

'String or binary data truncated' while inserting into SQL Server 2008

I am trying to create a basic WPF application that can store an encrypted password in SQL Server 2008 and also retrieve back the password when the user tries to login but I am getting an error after following this article
http://www.dreamincode.net/forums/topic/123865-one-way-encryption/
I read thru rainbow attacks and salting and hashing..
I tried some code but getting an error
The error I am getting is
string or binary data would be truncated
I read this article and tried to convert the textbox.text to string and also tried typing only one alphabet in the password texbox but still does not work ("I changed the connstring for security reasons as the connstring is working and there is no problem with that")
private void button1_Click(object sender, RoutedEventArgs e)
{
string strPassword;
SqlConnection cs= new SqlConnection("Data Source=STEVEJOBS;Initial Catalog=Test database;Integrated Security=True");
SqlDataAdapter da = new SqlDataAdapter();
da.InsertCommand = new SqlCommand("INSERT INTO Member_info(Name,Username,Password,Email,Member) VALUES(#Name,#Username,#Password,#Email,#Member)", cs);
da.InsertCommand.Parameters.Add("#Name", SqlDbType.NVarChar).Value = Name_tb.Text;
da.InsertCommand.Parameters.Add("#Email", SqlDbType.VarChar).Value = Email_tb.Text;
da.InsertCommand.Parameters.Add("#Username", SqlDbType.VarChar).Value = Username_tb.Text;
//MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
//byte[] hashedBytes;
//UTF8Encoding encoder = new UTF8Encoding();
//hashedBytes = md5Hasher.ComputeHash(encoder.GetBytes(strPassword));
//SqlParameter paramPwd;
//paramPwd = new SqlParameter("#Password", SqlDbType.Binary, 16);
//paramPwd.Value = hashedBytes;
//da.InsertCommand.Parameters.Add(paramPwd);
da.InsertCommand.Parameters.Add("#Password", SqlDbType.VarChar).Value = HashPassword(Password_tb.Text.ToString());
da.InsertCommand.Parameters.Add("#Member", SqlDbType.NText).Value =Myes_rb.Content ;
cs.Open();
da.InsertCommand.ExecuteNonQuery();
cs.Close();
MessageBox.Show("Sucessfully added");
}
static string HashPassword(string pasword)
{
byte[] arrbyte = new byte[pasword.Length];
SHA256 hash = new SHA256CryptoServiceProvider();
arrbyte = hash.ComputeHash(Encoding.UTF8.GetBytes(pasword));
return Convert.ToBase64String(arrbyte);
}
Thks for the help!
This error appears when you try to insert a string with more characters than specified in column definition. Make your string columns wider.
To identify column that triggers this error, You can change your INSERT statement by eliminating parameters one by one (remove da.InsertCommand.Parameters.Add line for that column and in VALUES part of INSERT statement put a constant like 'John').
EDIT#1:
Continue eliminating columns one by one (just like You did with password column) and once insert statement doesn't fail, You will know what column caused error. Then debug to find out the length of value you are assigning to (failing) column parameter. Length of that column in database must be >= than length of value You are trying to insert.
Another thing to note: at the time of writing your question, You thought that password column is problem, but maybe some other column is problem. And only solution to this error is to make all columns wide enough so values can be stored in them.
EDIT#2:
Use Password property to get text user typed in:
da.InsertCommand.Parameters.Add("#Password", SqlDbType.VarChar).Value =
HashPassword(Password_tb.Password);
To get the length of hashed password use this code instead:
string pwdHash = HashPassword(Password_tb.Password);
da.InsertCommand.Parameters.Add("#Password", SqlDbType.VarChar).Value = pwdHash;
Put breakpoint on the second line and check the length of pwdHash string. Password column in database table must be equal or greater to this length.
Ok, you are totally off. YOu ahve tons of issues. Lets start:
I am trying to create a basic WPF application that can store an encrypted password in the SQL
SERVER 2008 and also retrieve back the password when the user try's to login but i am getting an
error after following this article http://www.dreamincode.net/forums/topic/123865-one-way-
encryption/
Fail, fired. See, - one way hashing (NOT encryption) is called so because it is one way. NO WAY TO RETRIEVE THE PASSWORD WITHOUT BREAKING IT. Program will never work.
also tried typing only one alphabet in the password texbox but still doesnot work
Read the documentation how salting works. SHA converts the input into a binary randum number of specific length. It is totally irrelevant whether you feed it 1 or 1000 character long passwords, the result will always be a fixed lengh binary code.
return Convert.ToBase64String(arrbyte);
This is quite irregular. Most people will convert the arrays into HEX (fixed length, easy to read / write for debugging) and use this.
Anyhow, write out the LENGTH of the string you return here. CHeck all parameters you enter against table structure lengh. Finished.
And you still fail the homework - SHA is not retrievable without breaking.
basic WPF application that can store an encrypted password in the SQL SERVER 2008 and also
retrieve back the password when the user try's to login
will never be achieved with this approach.

ExecuteNonQuery returns 1 even if update statement didn't affect any row

I am facing a quite strange problem here.
My DAL was written using OdbcConnection objects and was perfectly working.
However I had to respect some requirements and therefore had to move the system to use MySqlConnection
Shouldn't give any problem, would you say.
However, there is a little misunderstanding now: when I execute an UPDATE command, without entering any new detail (let's say I change the user "test"'s username to... "test"), the command.ExecuteNonQuery() returns 1 anyway.
With the previous system & OdbcCommand objects, it returned 0 if no field changed.
Is it just a basic difference between the two systems or is there anything I've missed here?
Just some code even if it is very basic:
private readonly string _updateUserCommand =
"UPDATE user u " +
"JOIN city c ON c.Name=?City " +
"SET `City Id`=c.Id, u.Username=?Username WHERE u.Id=?Id";
// (...)
MySqlCommand command = null;
try
{
connection.Open();
//First step: storing the user in table user
//Creating the actual command:
command = new MySqlCommand(_updateUserCommand, connection);
command.Parameters.AddWithValue("?City", u.City);
command.Parameters.AddWithValue("?Username", u.Name);
command.Parameters.AddWithValue("?Id", u.Id);
int i = command.ExecuteNonQuery();
if (i != 0) return true;
else return false;
}
Your explanation doesn't make much sense. If you give a valid id and do an update on the username even if you update to the same name you can expect that 1 row will be affected. i.e. there is one row with the userId
ExecuteNonQuery returns the number of rows it changed, even if that change isn't noticeable to a human reader. The query did find a match and it did update one row. SQL really doesn't pay that much attention to what the old value was, it simply overwrites it and counts that as one row altered.

Get DateTime from SQL database

I have a DateTime record in my table in a database and I write a query to get it from the database:
string command2 = "select Last_Modified from Company_Data where Company_Name='" + DescriptionEntryForm.SelectedItem.ToString() + "'";
SqlCommand search_company2 = new SqlCommand(command2, con_string.con);
SqlDataReader company_reader2 = search_company2.ExecuteReader();
dateform.Text = company_reader2.GetValue(0).ToString();
company_reader2.Close();
But the penultimate statement throw an exception saying "Invalid attempt to read when no data is present".
How can I solve it?
Well, the immediate problem with your code is that you haven't called company_reader2.Read() to move the cursor onto the first row.
From the docs for SqlDataReader.Read:
The default position of the SqlDataReader is before the first record.
Therefore, you must call Read to begin accessing any data.
You should also note the return value of Read() which indicates whether or not you've read to the end of the record set.
Other problems:
You should put using statements around the SqlCommand and SqlDataReader, otherwise if there's an exception you won't be closing the connection. You may be able to get away with disposing the command and letting the reader just disappear automatically - but I typically dispose of both just so I don't need to think too carefully.
You're assuming that the format of date/time will be appropriate by just calling ToString with no format specifier.
You should use a parameterised SQL query to avoid SQL injection attacks.
It looks like you've executed the command, but haven't actually read from it.
company_reader2 = search_company2.ExecuteReader();
if (company_reader2 != null && company_reader2.HasRows) {
company_reader2.Read();
dateform.Text = company_reader2[0].ToString();
}

Categories

Resources