SqlDataReader reads every other row? - c#

I tried going through my code for hours trying to see where I went wrong and google doesn't seem to have the answer either.
Basically I am running this code:
public bool LoginRequest(string ReceivedUsername, string ReceivedPassword)
{
bool ValidLogin = false;
try
{
using (SqlConnection myConnection = new SqlConnection(ConnectString))
{
myConnection.Open();
Log.Debug("Succesful sql connection");
SqlCommand userSELECTcom = new SqlCommand("SELECT username,password FROM users;", myConnection);
SqlDataReader reader = userSELECTcom.ExecuteReader();
//verify login
while (reader.Read())
{
CompareUsername = reader["username"].ToString();
ComparePassword = reader["password"].ToString();
Log.Debug(ReceivedUsername + " against " + CompareUsername);
Log.Debug(ReceivedPassword + " against " + ComparePassword);
if (CompareUsername == ReceivedUsername && ComparePassword == ReceivedPassword)
{
ValidLogin = true;
Log.Debug(ReceivedUsername + " has logged in successfully!!!");
myConnection.Close();//close sql conn
reader.Close();//close sqldatareader
return ValidLogin;
}
else if (CompareUsername != ReceivedUsername || ComparePassword != ReceivedPassword)
{
if (!reader.Read())
{
Log.Debug(ReceivedUsername + " has not logged in successfully with password: " + ReceivedPassword);
myConnection.Close();//close sql conn
reader.Close();//close sql data reader
return ValidLogin;
}
}
}
//end of verify sequence
}
}
//logging any login request issues
catch (Exception e)
{
Log.Debug(e);
}
return ValidLogin;
}
I have a logging program set up that tells me everything thats happening as the code gets executed. These lines: " Log.Debug(ReceivedUsername + " against " + CompareUsername);
Log.Debug(ReceivedPassword + " against " + ComparePassword); "
helps me see which row is being checked by the reader. I tried with six rows each with unique usernames and passwords and the result basically shows that only row 1, 3 and 5 is checked by the reader against the input from the user. So if I tried to log in with my client using a username and password from row 2, 4 or 6 I get an error saying my log in failed. Can anyone explain why this happens?

You have an extra Reader.Read() call in your condition where you didn't find the login that time. That's skipping to the next record, then your main loop's Reader.Read() goes to the next.
You don't need to loop like this, though. Build a query that looks for a record by the username. If there are no records, login fails. If there is one, check the password.

You have a 2nd reader.Read() on the if statement inside the while block. That is causing your code to skip a record.

To keep things simple you could directly query from database.
Below is example code to check if the received username and password exists in the db:
string sql = #"SELECT username,password FROM users
WHERE username=#username and password = #password";
SqlCommand userSELECTcom = new SqlCommand(sql, myConnection);
userSELECTcom.Parameters.AddWithValue(#username, ReceivedUsername);
userSELECTcom.Parameters.AddWithValue(#password, ReceivedPassword);
using(SqlDataReader reader = userSELECTcom.ExecuteReader())
{
ValidLogin = reader.HasRows;
}

else if (CompareUsername != ReceivedUsername || ComparePassword != ReceivedPassword)
{
if (!reader.Read()) //remove this condition it will skip the current loop
{
Log.Debug(ReceivedUsername + " has not logged in successfully with password: " + ReceivedPassword);
myConnection.Close();//close sql conn
reader.Close();//close sql data reader
return ValidLogin;
}
}

Related

How do i make a message box appear if DBNULL occurs

I have a problem where if i search for data via a TextBox and the data doesn't exist in the database i get the error
'Object cannot be cast from DBNull to other types.'
I am trying to make a MessageBox appear to say data doesn't exist and cannot figure out how to do this.
I have tryed using an if statement where if the TextBox equals DBNull then a MessageBox appears. this doesnt work and im not too sure why. The error occurs with me trying to **equal** toDBNull. How do i produce aTextBox` saying data doesnt exist?
{
SqlConnection con = new SqlConnection("***COnString**");
con.Open();
SqlCommand comm = new SqlCommand("SELECT SUM (Total_Hours_Day) FROM Sign_In_Out_Table, User_Table WHERE User_Table.FirstName = '" + Search_Username_Alerts_Admin_txtbox.Text + "' AND Sign_In_Out_Table.eb_number = User_Table.eb_number AND Date between GETDATE()-14 and GETDATE()", con);
decimal TotalHoursFortnight = Convert.ToDecimal(comm.ExecuteScalar());
con.Close();
decimal sum = 0;
sum += Convert.ToDecimal(TotalHoursFortnight);
if (Search_Username_Alerts_Admin_txtbox.Text == DBNull)
{
MessageBox.Show("No Data Exists");
}
else
{
MessageBox.Show(Search_Username_Alerts_Admin_txtbox.Text + ":" + Environment.NewLine + " Hours Worked = " + TotalHoursFortnight, ("Working Info Admin"), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
My expected result is for a message box to appear saying data doesn't exist if searched for. but if it does the data will show in a message box.
You have 3 cases to implement:
No data at all: check for null
Invalid data, e.g. 1 + 2 + NULL + 3 == NULL: check for DBNull.Value
Valid data, e.g. 1 + 2 + 3 == 6: convert it with a help of Convert.ToDecimal()
Code:
// wrap IDisposable into using
using (SqlConnection con = new SqlConnection("***COnString**")) {
con.Open();
//DONE: Make sql readable
//DONE: Make sql parametrized
//TODO: you may want to change eb_number = eb_number into INNER JOIN
string sql =
#"SELECT SUM (Total_Hours_Day)
FROM Sign_In_Out_Table,
User_Table
WHERE User_Table.FirstName = #prm_FirstName
AND Sign_In_Out_Table.eb_number = User_Table.eb_number
AND Date BETWEEN GETDATE() - 14 AND GETDATE()";
using (SqlCommand comm = new SqlCommand(sql, con)) {
//TODO: Better specify RDBMS type explictly with "comm.Parameters.Add(...)"
comm.Parameters.AddWithValue(
"#prm_FirstName", Search_Username_Alerts_Admin_txtbox.Text);
var result = comm.ExecuteScalar();
if (null == result) { // No Data
MessageBox.Show("No Data Exist");
}
else if (DBNull.Value == result) { // We have the Data and it's RDBMS Null
MessageBox.Show("Data Exist, but not valid.");
}
else { // We have a valid Decimal
Decimal sum = Convert.ToDecimal(result);
//TODO: put the relevant code here
}
}
}
I would use decimal.tryparse to see if data was returned
SqlConnection con = new SqlConnection("***COnString**");
con.Open();
SqlCommand comm = new SqlCommand("SELECT SUM (Total_Hours_Day) FROM Sign_In_Out_Table, User_Table WHERE User_Table.FirstName = '" + Search_Username_Alerts_Admin_txtbox.Text + "' AND Sign_In_Out_Table.eb_number = User_Table.eb_number AND Date between GETDATE()-14 and GETDATE()", con);
string TotalHoursFortnight = (comm.ExecuteScalar()).ToString();
con.Close();
decimal sum = 0;
decimal temp;
if(!decimal.TryParse(TotalHoursFortnight, out temp))
{
MessageBox.Show("No Data Exists");
}
else
{
sum += temp;
MessageBox.Show(Search_Username_Alerts_Admin_txtbox.Text + ":" + Environment.NewLine + " Hours Worked = " + TotalHoursFortnight, ("Working Info Admin"), MessageBoxButtons.OK, MessageBoxIcon.Information);
}
You need check null for query result
var result = comm.ExecuteScalar();
if(result != null){
decimal TotalHoursFortnight = Convert.ToDecimal(comm.ExecuteScalar());
// move remain code to if block
}
And if (Search_Username_Alerts_Admin_txtbox.Text == DBNull) should change to
if (Convert.IsDBNull(Search_Username_Alerts_Admin_txtbox.Text){
}

+1 to data column using SQL Server Compact 4.0

I am trying to create a simple button, that when clicked, adds 1 to the related column. I use a dropdown box to select the ID, then add 1 to the value. However, I am presented with the error:
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in System.Data.SqlServerCe.dll
and it highlights cm.ExecuteNonQuery();
I have gone through several attempts at this but it's getting me a little confused as to why I can't simply run the SQL statement.
Here is the code
private void button2_Click(object sender, EventArgs e) {
try {
SqlCeCommand cm = new SqlCeCommand("UPDATE fixedBugs SET Success = Success + 1 WHERE Fixed_ID = '" + comboBox1.Text, mySqlConnection);
cm.ExecuteNonQuery();
} catch (SqlCeException) {
MessageBox.Show("Error");
}
}
"UPDATE fixedBugs SET Success = Success + 1 WHERE Fixed_ID = '" + comboBox1.Text + "'"
Need to close the string parameter with ' in query?
Your command has a opening apostrophe which is not being closed. This should fix it.
SqlCeCommand cm = new SqlCeCommand("UPDATE fixedBugs SET Success = Success + 1 WHERE Fixed_ID = '" + comboBox1.Text + "'", mySqlConnection);
But that's a security issue since the user can manage to add extra commands to your query, which could ruin your entire database.
This is a better solution since using parameters is more safe.
SqlCeCommand cm = new SqlCeCommand("UPDATE fixedBugs SET Success = Success + 1 WHERE Fixed_ID = #fixedid;", mySqlConnection);
cm.Parameters.AddWithValue("#fixedid", comboBox1.Text);
This will prevent future headaches.
This question has better detailed answers that may help enlighten your mind...
You need to think about below things;
User must select a value.
Security
Dispose the command after using it.
string selectedValue = comboBox1.Text;
if (string.IsNullOrEmpty(selectedValue))
{
MessageBox.Show("Please select something");
return;
}
string sql = "UPDATE fixedBugs SET Success = ISNULL(Success,0) + 1 WHERE Fixed_ID = #selectedValue";
try
{
using (SqlCeCommand cm = new SqlCeCommand(sql, mySqlConnection))
{
SqlCeParameter param = new SqlCeParameter("#selectedvalue", SqlDbType.NText);
cm.Parameters.Add(param);
cm.Parameters["#selectedvalue"].Size = 50;
cm.Parameters["#selectedvalue"].Value = selectedValue.Trim();
cm.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
PS: Code is not tested.

I keep getting "Invalid attempt to read when no data is present" even though I am sure a record exist

I have been trying to figure out why I am getting this error message and it's driving me up the wall cause I think I have applied all that is needed to get the result I desire. What can I do to accomplish this.
private void btnLogin_Click(object sender, EventArgs e)
{
try
{
// Receive user input from login screen
string username = txtUsername.Text;
string password = txtPassword.Text;
// Test if user input is null or white space aka empty
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
MessageBox.Show("Please enter both username and password");
else
{
// Establish connection with database
SqlConnection cn = new SqlConnection(#"SERVER=KACY-PC\SQLEXPRESS2014;DATABASE=hardwareMgmt;Integrated Security=True");
cn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
string strSQL = "SELECT * FROM tbl_user WHERE username = '" + username + "' AND password = '" + password + "'";
cmd.CommandText = strSQL;
SqlDataReader dr = cmd.ExecuteReader();
// Count number of record
int count = 0;
while (dr.Read())
count += 1; MessageBox.Show(Convert.ToString(count));
dr.Read();
// Validate whether user has logged in before and display appropriate
if (count == 1 && dr["first_login"].ToString() == "N")
MessageBox.Show("Welcome back '" + dr["first_name"].ToString() + "' '" + dr["last_name"].ToString() + "'", "Welcome back", MessageBoxButtons.OK);
else if (count == 1 && dr["first_login"].ToString() == "Y")
MessageBox.Show("Hello " + dr["first_name"].ToString() + "' '" + dr["last_name"].ToString() +
"\nIt appears that you are logging in for the first time" +
"\nor your password got reset", "Welcome", MessageBoxButtons.OK, MessageBoxIcon.Information);
else if (count > 1)
MessageBox.Show("Duplication in user account \nPlease contact System Administrator", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
MessageBox.Show("Invalid Username or Password", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I Keep getting the following result after I enter the credentials in the login window. I am sure that the record is found in the database but it just not reading it.
Your
dr.Read();
line is unnecessary since after your
while (dr.Read())
count += 1; MessageBox.Show(Convert.ToString(count));
code, there will be no next record to read, that's why you get this error.
As Ivan commented, you can not read any data after your while. That's why, whatever wanna read first_login, first_name, last_name etc.. columns, you have to read while you iterating your reader. That's why consider to change your logic first.
And for myself, I prefer to use GetXXX methods of SqlDataReader when I wanna read the values instead of dr[...] syntax. That makes more readable in my opinion.
A few things more;
You should always use parameterized queries by the way. This kind of string concatenations are open for SQL Injection attacks.
Do not store your passwords as a plain text. Read: Best way to store password in database
Use using statement to dispose your connection, command and reader automatically.

C# reading int from mysql

Having problem reading a value from my table in mysql, is the index value i cant read the value back no matter what. all i get is the initialized value of 0 i dont get any error because it return 0, if i run the query in the database it get the correct value. i tried to use executeScalar() but with the same result .
MySqlConnection conn = new MySqlConnection(MyConString);
ulong ukey=0;
try
{
string sql_users2 = "SELECT `key` FROM `permuser` WHERE `user` = '" + myuser + "' AND `code` = '" + mycode + "'";
MySqlCommand cmdSel2 = new MySqlCommand(sql_users2, conn);
conn.Open();
MySqlDataReader dr2 = cmdSel2.ExecuteReader();
dr2.Read();
ukey = dr2.GetUInt64(dr2.GetOrdinal("key"));
// MessageBox.Show("Sorry " + myuser + " already have access to " + mycode + ",\nIf this is an extension, search for the user which key is " + ukey + " and edit the end date.", "Duplicate User Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
dr2.Close();
dr2.Dispose();
}
catch (MySqlException ex) //catch 2
{
MessageBox.Show("catch ukey\nCan't connect to database\n" + ex.ToString());
}
conn.Close();
conn.Dispose();
You are returning a single value from your query, so you could use directly ExecuteScalar instead of ExecuteReader. (the link point to the description for SqlServer, but it is the same for MySql)
An important question to never forget is the usage of parameters instead of string concatenation.
What happen if your myuser or mycode variables contain a single quote? You get wrong results or syntax errors.
Of course, the main problem is the Sql Injection attack to never understimate.
using(MySqlConnection conn = new MySqlConnection(MyConString))
{
ulong ukey=0;
try
{
string sql_users2 = "SELECT `key` FROM `permuser` WHERE `user` = #usr AND `code` = #code";
MySqlCommand cmdSel2 = new MySqlCommand(sql_users2, conn);
conn.Open();
cmdSel2.Parameters.AddWithValue("#usr", myuser);
cmdSel2.Parameters.AddWithValue("#code", mycode);
object result = cmdSel2.ExecuteScalar();
if(result != null)
ukey = Convert.ToUInt64(result);
}
catch (MySqlException ex) //catch 2
{
MessageBox.Show("catch ukey\nCan't connect to database\n" + ex.ToString());
}
}
also I am a bit perplexed about your usage of UInt64. What kind of datatype is stored in the key column?
way is many simply:
ukey = (uint)dr2[0];

When ASP.NET username exists, change to username(x)

Using SQL Membership Provider for ASP.NET membership. I'm using first.last as the username, which is created programmatically from the user details filled in on a form.
When user submits the form, I want to be able to check if the username exists, and change it to username1 if it does, check username1 exists, and make it username2 if it exists, etc. until it is a unique username.
I don't know how to do stored procedures, so I'm trying to use a SQLDataReader to check if username exists.
The problem is my loop. The logic is basically to set a boolean and keep looping and adding 1 to the counter, until it doesn't find a duplicate. I have stepped through this many times, and even when it sets the boolean to false, it keeps looping.
Ideas please?
Code behind:
protected void Membership_add()
{
SqlConnection con = new SqlConnection(connectionString);
string NewUserNameString = FirstName.Text + "." + LastName.Text;
//Check for duplicate aspnet membership name and add a counter to it if exists
// Check for valid open database connection before query database
bool match = true;
SqlDataReader _SqlDataReader = null;
string TestNameString = NewUserNameString;
string selectDupeString = "SELECT UserId FROM aspnet_Users WHERE UserName = '" + TestNameString + "'";
SqlCommand SQLdatareaderCmd = new SqlCommand(selectDupeString, con);
int UserNameCounter = 0;
con.Open();
while (match = true)
{
//Open the connection
try
{
//Read the table
_SqlDataReader = SQLdatareaderCmd.ExecuteReader();
}
catch (Exception ex)
{
lblDatareaderEx.Text = "An Exception occurred. " + ex.Message + " " + ex.GetType().ToString();
}
if (_SqlDataReader.HasRows)
{
//match = true;
//increase counter by 1 for each record found and change First.Name to First.Namex
TestNameString = NewUserNameString;
UserNameCounter = UserNameCounter + 1;
TestNameString = TestNameString + UserNameCounter.ToString();
_SqlDataReader.Close();
_SqlDataReader.Dispose();
selectDupeString = "SELECT UserId FROM aspnet_Users WHERE UserName = '" + TestNameString + "'";
SQLdatareaderCmd = new SqlCommand(selectDupeString, con);
}
else
{
// close sql reader
_SqlDataReader.Close();
_SqlDataReader.Dispose();
//get out of loop
match = false;
}
}
con.Close();
con.Dispose();
}
This line:
while (match = true)
does an assignment.
If you want your code to work you have to do a comparison:
while (match == true)
Or, since your variable is already a bool, you can just use the variable directly:
while(match)
At the moment you're setting match rather than comparing it's value.
Try setting while (match = true) to while (match == true)
If you break your code out into smaller blocks, the code becomes simpler and easer to read.
private string MembershipAddUser(string firstName, string lastName)
{
string username = firstName + "." + lastName;
int i = 0;
while (UserExists(username))
{
i++;
username = firstName + "." + lastName + i.ToString();
}
return username;
}
private bool UserExists(string username)
{
string sql = "SELECT COUNT(*) FROM dbo.aspnet_Users WHERE UserName = #UserName";
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("#UserName", username);
using (connection)
{
connection.Open();
int count = (int) command.ExecuteScalar();
return (count != 0);
}
}

Categories

Resources