I've written this registration form which adds data to my SQL Server database. What I want is an exception when the user enters a username that is already in the database.
protected void Button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection conn2 = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString);
conn2.Open();
string CheckUser = "select Username from UserData where Username like #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn2);
com2.Parameters.AddWithValue("#Username", "'%"+ UsernameTextBox.Text +"%'");
com2.ExecuteNonQuery();
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
conn2.Close();
if (IsMatch == 0)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString);
conn.Open();
string InsertQuery = "insert into UserData (Username, Email, Password, Country) values (#Username, #Email, #Password, #Country)";
SqlCommand com = new SqlCommand(InsertQuery, conn);
com.Parameters.AddWithValue("#Username", UsernameTextBox.Text);
com.Parameters.AddWithValue("#Email", EmailTextBox.Text);
com.Parameters.AddWithValue("#Password", PasswordTextBox.Text);
com.Parameters.AddWithValue("#Country", CountryDropDownList.SelectedItem.ToString());
com.ExecuteNonQuery();
Response.Redirect("Manager.aspx");
conn.Close();
}
else
{
Response.Write("User Already Exists!");
}
}
catch (Exception ex)
{
Response.Write(Convert.ToString(ex));
}
}
When I run it, I get an exception on the following line:
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
Blam's second solution works, but the IsMatch can be simplified a bit by casting to int instead of going to string and parsing.
This should also be handled at the database level. Set a primary key on your username column:
ALTER TABLE UserData ADD CONSTRAINT
PK_UserData PRIMARY KEY CLUSTERED (Username)
If you do it this way, then you don't even have to check for duplicates explicitly, you can just try to create the user and handle the exception if it fails:
try
{
using (var conn = new SqlConnection((ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString)))
{
conn.Open();
#if DOUBLE_CHECK
string CheckUser = "select count(*) from UserData where Username = #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn);
com2.Parameters.AddWithValue("#Username", UsernameTextBox.Text);
if ((int)com2.ExecuteScalar() > 0)
{
Response.Write("User already exists");
return;
}
#endif
string InsertQuerry = "insert into UserData (Username,Email,Password,Country) values (#Username,#Email,#Password,#Country)";
SqlCommand com = new SqlCommand(InsertQuerry, conn);
com.Parameters.AddWithValue("#Username", UsernameTextBox.Text);
com.Parameters.AddWithValue("#Email", EmailTextBox.Text);
com.Parameters.AddWithValue("#Password", PasswordTextBox.Text);
com.Parameters.AddWithValue("#Country", CountryDropDownList.SelectedItem.ToString());
com.ExecuteNonQuery();
Response.Redirect("Manager.aspx");
}
}
catch (SqlException se)
{
if (se.Errors.OfType<SqlError>().Any(e => e.Number == 2627))
{
Response.Write("User already exists");
}
else
{
Response.Write(se.ToString());
}
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
If you handle the exception this way, the #if DOUBLE_CHECK section is redundant and can be removed. An attempt to add duplicate name will cause a SQL error and exception, and this will detect and handle the "duplicate key" error.
Two unrelated notes on your code:
Response.Redirect() will abort the current thread and your conn.Close() will not be called. Use a using() to ensure it's called.
Storing a password in the database as plain text is a disaster waiting to happen. PLEASE take a look at Best way to store password in database for some ideas about how to do this correctly
That won't return an integer
string CheckUser = "select count(*) from UserData where Username like #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn2);
com2.Parameters.AddWithValue("#Username", "'%"+ UsernameTextBox.Text +"%'");
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
And you don't need to use two different connections.
Just use one and close it in a Finally.
string CheckUser = "select count(*) from UserData where Username = #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn2);
com2.Parameters.AddWithValue("#Username", UsernameTextBox.Text );
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
This returns 0 or 1. This should fix your issue. Looks like you need to return an int type. Or you could change it to bool if you want. Either way, this sql statement should help! :)
select
isnull(convert(bit,(select top 1 case
when username != '' then 1
else 0 end
from UserData
where username like #Username)),0)
Related
I started to learn ASP.NET. I create a register system, and when I try to check if the username or email already exists in the database, it's not checked and creates the user even when you have it already.
try
{
conn.Open();
bool exists = false;
string checkuser = "SELECT count(*) FROM accounts WHERE username='" + username.Text + "'";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("username", username.Text);
exists = (int)cmd2.ExecuteScalar() > 0;
if (exists)
{
Response.Write("User already exists");
}
string command = "INSERT INTO accounts (username, email, password) VALUES (#username, #email, #password)";
SqlCommand cmd = new SqlCommand(command, conn);
cmd.Parameters.AddWithValue("#username", username.Text);
cmd.Parameters.AddWithValue("#email", email.Text);
cmd.Parameters.AddWithValue("#password", password.Text);
cmd.ExecuteNonQuery();
}
catch(Exception)
{
label_msg.Visible = true;
label_msg.Text = "Something went wrong....";
throw;
}
finally
{
Response.Redirect("/layout.aspx");
conn.Close();
}
Thanks !
string checkuser = "if exists (select 1 from accounts where username=#username) select 1 else select 0 end";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("#username", username.Text);
bool exists = (int)cmd2.ExecuteScalar() > 0;
Having SQL Server check for the existence of matches will stop at the first match instead of potentially returning a set of matches and then it is simply returning a value accordingly. This will minimize data transferred between the server and your software plus avoid performing a count when we really just care if there are any matches.
whenever you want to find TRUE/FALSE value or counting the no records always use COUNT(1).
bool exists = false;
string checkuser = "SELECT count(*) FROM accounts WHERE username=#username;";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("#username", username.Text);
object result = cmd2.ExecuteScalar();
if (result != null)
exists = (Convert.ToInt32(result) == 1) ? true : exists;
if (exists)
{
Response.Write("User already exists");
}
Check if user Exist already
int exists = 0;
string checkuser = "SELECT count(*) FROM accounts WHERE username='" +username.Text + "'";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("username", username.Text);
exists = (int)cmd2.ExecuteScalar();
if (exists>0)
{
Response.Write("User already exists");
}
The error I'm getting is pointing to when I call
cmd.BeginTransaction(IsolationLevel iso);
error description click here
This method is called the the user tries to sign up on log in webpage. If HTML5 client-side input verification is accepted and both password fields match, this method is called and empty textboxes are filled with a space (" ").
This is for my senior project, please help.
//this method adds a record to the table customers
public Boolean addUser(String email, String password, String name, String phone, String company, String address, String city, String state, String zip)
{
MySqlConnection conn = new MySqlConnection(connString);
MySqlCommand cmd = conn.CreateCommand();
MySqlTransaction trans = conn.BeginTransaction(IsolationLevel.Serializable);
cmd.Connection = conn;
cmd.Transaction = trans;
try {
conn.Open();
//these are the mandatory fields to be inserted)
string sql = "Insert into customers(name,password,phone,email) values (?name,?password,?phone,?email)";
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("?name", name);
cmd.Parameters.AddWithValue("?email", email);
cmd.Parameters.AddWithValue("?phone", phone);
cmd.Parameters.AddWithValue("?password", password);
cmd.ExecuteNonQuery();
trans.Commit();
conn.Close();
conn = new MySqlConnection(connString);
cmd = conn.CreateCommand();
cmd.Connection = conn;
//these fields are optional and if input is empty they are being passed as " "
sql = "Update customers Set username = ?company, address=?address ,city=?city, state=?state, zipcode=?zip where customerID=MAX(customerID)";
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("?company", company);
cmd.Parameters.AddWithValue("?address", address);
cmd.Parameters.AddWithValue("?city", city);
cmd.Parameters.AddWithValue("?state", state);
cmd.Parameters.AddWithValue("?zip", zip);
cmd.ExecuteNonQuery();
conn.Close();
}
catch (MySqlException ex)
{
trans.Rollback();
errorcode = ex.Number;
MessageBox.Show("7. Sign Up Failure\nError code: " + getError(), "Sign Up failure", MessageBoxButtons.OK, MessageBoxIcon.Error);
conn.Close();
return false;
}
return true;
}
Update:
IF I don't include the transaction methods, the error i'll get is when I perform the second database transaction (cmd.ExecuteNonQuery())
See error picture
It would be nice to implement the IsolationLEvel Serializable since it stops other Database transactions from occurring at the same time. But at this point I'm just trying to get users to sign up.
I have to make a simple login that will not crash when you insert into the browser a (") so i needed to parameterize the query string but for some reason im gettin an error saying:
Must declare the scalar variable "#UserName"
here is the code
private void DoSqlQuery()
{
try
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["RolaConnectionString"].ConnectionString);
conn.Open();
string checkUser = "select * from UserData where UserName = #UserName";
SqlCommand com = new SqlCommand(checkUser, conn);
com.Parameters.AddWithValue("#Username", txtUserName.Text.Trim());
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPassword = "select Password from UserData where UserName = #UserName";
SqlCommand passConn = new SqlCommand(checkPassword, conn);
com.Parameters.AddWithValue("#Username", txtUserName.Text.Trim());
string password = passConn.ExecuteScalar().ToString();
conn.Close();
if (password == txtPassword.Text)
{
Session["New"] = txtUserName.Text;
Response.Write("Password is correct");
Response.Redirect("~/LoggedIn.aspx");
}
else
{
Response.Write("Password is not correct");
}
}
else
{
Response.Write("Username is not correct");
}
}
catch(Exception e)
{
Response.Write(e.ToString());
}
}
You are referencing the wrong command in the inner if statement:
string checkPassword = "select Password from UserData where UserName = #UserName";
SqlCommand passConn = new SqlCommand(checkPassword, conn);
com.Parameters.AddWithValue("#Username", txtUserName.Text.Trim());
^^^-- should be passConn
As a result, your second command never gets the parameter added so you get the error you mention. Case sensitivity may also be a problem, but it depends on the collation of your database - SQL Server is case-insensitive by default.
Some other suggestions not related to your problem:
Wrap commands and connection in using statements
Query the username and password in one query (WHERE UserName = #UserName AND Password = #Password). Hackers will first search for valid usernames, then try to hack the password using dictionary attacks. Trying to find a matching combination is much harder.
Do not store your passwords in plain text - use a salted hash
Or just use built-in security providers rather than rolling your own.
i had the exact name in my database yet i still keep getting that error as titled.
An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code
Image Link : http://i.imgur.com/tKtvlfj.png
Additional information: Invalid column name 'Username'.
protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ERegistrationConnectionString"].ConnectionString);
conn.Open();
string checkuser = "select count(*)from Employer where Username='" + TextBoxELUsername.Text + "'";
SqlCommand com = new SqlCommand(checkuser, conn);
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPasswordQuery = "select password from Employer where Username='" + TextBoxELUsername.Text + "'";
SqlCommand passComm = new SqlCommand(checkPasswordQuery, conn);
string password = passComm.ExecuteScalar().ToString().Replace(" ","");
if (password == TextBoxLoginPassword.Text)
{
Session["New"] = TextBoxELUsername.Text;
Response.Write("Password is Correct");
}
else
{
Response.Write("Password Incorrect");
}
}
else
{
Response.Write("Username Incorrect");
}
}
Your SQL is invalid. You forgot a space between the count(*) and from keyword. Try this instead:
select count(*) from Employer where Username=
Also you should change your sql to not allow sql injections and use the Parameters object
In the case of your Sql statement to retrieve the count(*) you really should Parameterize that statement to prevent sql injection.
string checkuser = #"select count(*)from Employer where Username= ?";
SqlCommand com = new SqlCommand(checkuser, conn);
comm.Parameters.AddWithValue("?", TextBoxELUsername.Text );
In addition try returning the variable temp in this fashion.
int temp = (int)comm.ExecuteScalar();
Beyond that I would try creating a second connection contained within the IF statement. It may sound odd but that connection can be stripped out of memory before the IF statement is triggered and in turn the program has no idea what connection your are trying to open.
You could avoid a second connection all together by creating a single sql statement
string checkuser = #"select count(*)from Employer where Username= ? and password = ?";
SqlCommand com = new SqlCommand(checkuser, conn);
comm.Parameters.AddWithValue("?", TextBoxELUsername.Text );
comm.Parameters.AddWithValue("?", TextBoxLoginPassword.Text );
your count return will only exist is both the username and password are correct.
You may also want to use the following code to force case sensitivity on your query
alter database your_database collate Latin1_General_CS_AS
I want to create a Registration and Log In form on Visual Studio 2010 (with Visual C#).
I have created Service-Based Database and one table. I can insert data into the table (at the registration form), but I cannot figure out how to log in the user.
I have a very simple Log In Form (just fields for username and password) and a 'Log In' Button. I do not really know how to check if the password and the username (that exist in my database) match. Here is what I have so far:
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text != "" & textBox2.Text != "")
{
cn.Open(); // cn is the Sqlconnection
cmd.Parameters.AddWithValue("#Username", textBox1.Text); // cmd is SqlCommand
cmd.Parameters.AddWithValue("#Password", textBox2.Text);
if (cmd.CommandText == "SELECT * FROM Table1 WHERE username = #Username AND password = #Password")
{
MessageBox.Show("Loggen In!");
this.Close();
}
cn.Close();
}
}
You need to Execute the query to know if the information exists in the database
if (textBox1.Text != "" & textBox2.Text != "")
{
string queryText = #"SELECT Count(*) FROM Table1
WHERE username = #Username AND password = #Password";
using(SqlConnection cn = new SqlConnection("your_connection_string"))
using(SqlCommand cmd = new SqlCommand(queryText, cn))
{
cn.Open();
cmd.Parameters.AddWithValue("#Username", textBox1.Text);
cmd.Parameters.AddWithValue("#Password", textBox2.Text);
int result = (int)cmd.ExecuteScalar();
if (result > 0)
MessageBox.Show("Loggen In!");
else
MessageBox.Show("User Not Found!");
}
}
I have also changed something in your code.
Changed the query text to return just the count of the users with the
specific username and account and be able to use ExecuteScalar
Enclosed the creation of the SqlConnection and SqlCommand in a using
statement to be sure to dispose these objects at the end of the
operation
I also recommend to change the the way in which you store the password.
Store, in the password field, an hash not the clear password. Then pass to the database the same hash and compare this against the content of the database field.
In this way, the password is known only to your user, not by you or by any passersby that looks at the database table
SqlConnection con = new SqlConnection("connection_string");
SqlCommand cmd = new SqlCommand("select Count(*) from [dbo].[Table] where uname=#uname and password=#password");
cmd.Connection = con;
con.Open();
cmd.Parameters.AddWithValue("#uname", uname.Text);
cmd.Parameters.AddWithValue("#password", password.Text);
int Result=(int)cmd.ExecuteScalar();
if (Result > 0)
{
Response.Redirect("welcome.aspx");
}
else
{
Response.Redirect("register.aspx");
}