C#.net Error at BeginTransaction (?) (MySQL) - c#

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.

Related

I need to update my database values using c#. But there is an error message when running. What can be the reason?

I have four text box values called txtName, txtId, txtAdd, txtTel. I need to update an existing record in my database table. But the code is not working. Can someone help me to identify my errors. Here is my code.
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\User\documents\visual studio 2012\Projects\WindowsFormsApplication1\WindowsFormsApplication1\Database4.mdf;Integrated Security=True");
try
{
String name = txtName.Text;
String id = txtId.Text;
String address = txtAdd.Text;
String tel = txtTel.Text;
String SqlQuery = "UPDATE [Table]VALUES (#id,#name,#tel,#address)";
SqlCommand cmnd = new SqlCommand(SqlQuery, con);
con.Open();
cmnd.ExecuteNonQuery();
MessageBox.Show("Saved Successfully");
}
catch (Exception ex)
{
MessageBox.Show("Error occured while saving" + ex);
}
finally
{
con.Close();
}
Plese help me
Your update Syntax is wrong. Also add the parameters to your command:
SQL UPDATE Syntax:
UPDATE table_name SET column1=value1,column2=value2,...
WHERE some_column=some_value;
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\User\documents\visual studio 2012\Projects\WindowsFormsApplication1\WindowsFormsApplication1\Database4.mdf;Integrated Security=True");
try
{
String name = txtName.Text;
String id = txtId.Text;
String address = txtAdd.Text;
String tel = txtTel.Text;
String SqlQuery = "UPDATE [Table] SET name = #name, tel = #tel, [address] = #address where [id] = #id";
SqlCommand cmnd = new SqlCommand(SqlQuery, con);
cmnd.Parameters.AddWithValue("#id", id);
cmnd.Parameters.AddWithValue("#name", name);
cmnd.Parameters.AddWithValue("#tel", tel);
cmnd.Parameters.AddWithValue("#address", address);
con.Open();
cmnd.ExecuteNonQuery();
MessageBox.Show("Saved Successfully");
}
catch (Exception ex)
{
MessageBox.Show("Error occured while saving" + ex);
}
finally
{
con.Close();
}
Your update query is wrong. Please see some examples.
After assigning your TextBox values to some strings, make sure that you use them after that.
You don't need to write (in your case) finally{} block manually, use using() statement instead of that.
Put your SqlCommand into using().
Use parameterized queries
Try this:
try
{
using(SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\User\documents\visual studio 2012\Projects\WindowsFormsApplication1\WindowsFormsApplication1\Database4.mdf;Integrated Security=True"))
{
con.Open();
using(SqlCommand cmnd = con.CreateCommand())
{
// Your update query must look like something like this
cmnd.CommandText = #"UPDATE [Table]
SET Name = #name,
Tel = #tel,
Address = #address
WHERE Id = #id";
cmd.Parameters.Add(new SqlParameter("#id", txtId.Text));
cmd.Parameters.Add(new SqlParameter("#name", txtName.Text));
cmd.Parameters.Add(new SqlParameter("#tel", txtTel.Text));
cmd.Parameters.Add(new SqlParameter("#address", txtAdd.Text));
cmnd.ExecuteNonQuery();
MessageBox.Show("Saved Successfully");
}
}
}
catch(Exception ex)
{
//Handle your exception here
}
I guess you could try adding these lines of code to add parameters:
cmnd.Parameters.Add(new SqlParameter("#id", id);
cmnd.Parameters.Add(new SqlParameter("#name", name);
cmnd.Parameters.Add(new SqlParameter("#tel", tel);
cmnd.Parameters.Add(new SqlParameter("#address", address);

How to return true if name and password both match? (MySQL/C#)

I am currently working on a simple login system with C# and MySQL and I have everything working so far but I can't seem to get the login verification working, I can't work out the correct way of checking the records in the table as I have tried a few different ways that I found online but none were working.
public bool loginCorrect(String name, String password)
{
if (this.OpenConnection() == true) {
using (MySqlCommand cmd = new MySqlCommand ("SELECT * FROM logins WHERE name = #UserName AND password = #Password")) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Now we are going to read the data imput
MySqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
bool isExist = myLoginReader.HasRows();
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
This is the current code for the login verification which doesn't work. I want the boolean to return true when the passed parameters name and password match which the ones in the database table 'logins'.
Below is my working Insert method just in case you need to compare the structure.
public void Insert(String username, String password)
{
string query = "INSERT INTO logins (name, password) VALUES ('" + username + "','" + password + "')";
//open connection
if (this.OpenConnection () == true)
{
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
EDIT:
I have altered the loginCorrect method as suggested and I get these errors when compiling:
bool isExist = myLoginReader.HasRows(); // Non-Invocable member 'System.Data.Common.DbDataReader.HasRows' cannot be used like a method.
And:
return isExist; // The name 'isExist' does not exist in the current context.
EDIT 2
Current Code
public void Insert(String name, String password)
{
//open connection
if (this.OpenConnection())
{
string query = "INSERT INTO logins (name, password) VALUES (#UserName, #Password)";
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Add parameters
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
public bool loginCorrect(String name, String password)
{
bool isExist = false;
if (this.OpenConnection()) {
using (MySqlCommand cmd = new MySqlCommand ("SELECT * FROM logins WHERE `name` = #UserName AND password = #Password")) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Now we are going to read the data imput
MySqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
isExist = myLoginReader.HasRows;
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
Which gives
System.InvalidOperationException: Connection must be valid and open.
SOLUTION
public void Insert(String name, String password)
{
//open connection
if (this.OpenConnection())
{
string query = "INSERT INTO logins (name, password) VALUES (#UserName, #Password)";
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Add parameters
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
public bool loginCorrect(String name, String password)
{
bool isExist = false;
if (this.OpenConnection()) {
using (MySqlCommand cmd = new MySqlCommand ("SELECT * FROM logins WHERE `name` = #UserName AND password = #Password", connection)) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", password);
//Now we are going to read the data imput
MySqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
isExist = myLoginReader.HasRows;
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
The problem was not passing the connection in the loginCorrect method
Try this, combined with some of the comments we gave you:
User check:
public bool loginCorrect(String name, String HASHED_AND_SALTED_PASSWORD)
{
bool isExist;
if (this.OpenConnection()) {
using (SqlCommand cmd = new SqlCommand ("SELECT * FROM logins WHERE `name` = #UserName AND password = #Password")) {
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", HASHED_AND_SALTED_PASSWORD);
//Now we are going to read the data imput
SqlDataReader myLoginReader = cmd.ExecuteReader ();
//if the data matches the rows (username, password), then you enter to the page
isExist = myLoginReader.HasRows;
//Close Reader
myLoginReader.Close ();
}
//Close Connection
this.CloseConnection ();
}
return isExist;
}
If you return inside the if, the connections won't be closed.
Insert - I'm not too experienced with C# classes, hope I did it correctly.
public void Insert(String username, String password)
{
//Hash and salt password here (this is pseudo code)
String HASHED_AND_SALTED_PASSWORD = StrongHash(password + GenerateSalt());
//open connection
if (this.OpenConnection())
{
string query = "INSERT INTO logins (`name`, password) VALUES (#UserName, #Password)";
//Create command and assign query
MySqlCommand cmd = new MySqlCommand(query, connection);
//Add parameters
cmd.Parameters.AddWithValue ("#UserName", name);
cmd.Parameters.AddWithValue ("#Password", HASHED_AND_SALTED_PASSWORD);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
A few other things - Make sure you store a properly hashed and salted password, using a strong hashing algorithm. Even if this is for a school project, you'd want to get used to best practices.
I've fixed a few unnecessary things I saw like if (this.OpenConnection() == true).
Let us know if this works.
EDIT:
Sorry, my bad. HasRows is a property, not a function. Try this instead: myLoginReader.HasRows; (Removed parentheses)
Also, declare Bool isExist at the top.

How to check if SQL database already has the entered Username?

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)

Database not storing information properly, stores info on different rows

The database is not storing information all on the same row. On the first page, when I click the button it records it and that's fine, it's stored. Then on the next page, when i click the button, it stores the information, but on a different row? Any solutions? Heres the problem, and code below.
PAGE 1
public void addInformationToDatabase()
{
string Sex = ddlGender.Text;
string Name = tbxName.Text;
string DOB = tbxDOB.Text;
string connectionString = WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
SqlConnection Con = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
command.Connection = Con;
command.CommandType = CommandType.Text;
command.CommandText = "INSERT INTO [User] (GenderID,Name,DOB) VALUES(#Sex,#Name,#DOB)";
command.Parameters.AddWithValue("#Sex", Sex);
command.Parameters.AddWithValue("#Name", Name);
command.Parameters.AddWithValue("#DOB", DOB);
try
{
Con.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
finally
{
Con.Close();
}
}
2ND PAGE
public void save()
{
string checkboxSelection = CheckBoxList1.SelectedItem.ToString();
string connectionString = WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
SqlConnection Con = new SqlConnection(connectionString);
SqlCommand c = new SqlCommand();
c.Connection = Con;
c.CommandType = CommandType.Text;
c.CommandText = "INSERT INTO [User] (Ans1) VALUES(#Ans1)";
c.Parameters.AddWithValue("#Ans1", checkboxSelection);
try
{
Con.Open();
c.ExecuteNonQuery();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
finally
{
Con.Close();
}
}
Any help appreciated
your first page needs to get the ID back following the insert and then your second page needs to do an update based on that ID, not a subsequent insert.
There are a lot of resources about getting ids back - e.g How to get last inserted id?
(I'm assuming the id field uniquely identifies your row)
first query -
c.CommandText = "INSERT INTO [User] (Ans1) VALUES(#Ans1); SELECT SCOPE_IDENTITY()";
...
int userID = (Int32) c.ExecuteScalar();
you'll need to pass that ID to your 2nd page and change the insert to be an update:
"UPDATE User] SET Ans1 = #Ans1 WHERE Id = #id";
you'll also need to add the id as a parameter
c.Parameters.AddWithValue("#id", userID);

Duplicate entries in database. ASP.NET - C# - SQL Server 2012

Question: data gets duplicated when inserting into database. How do I not make duplicate entries in database?
I read about securing/ preventing SQL injection by not using the
texboxt1.text
So I tried using
parameters.add()
But the entries are duplicated for every insertion.
This is the image of the database...
This is my code
protected void Button1_Click(object sender, EventArgs e)
{
string username = txtuser.Text;
string firstname = txtfirst.Text;
string lastname = txtlast.Text;
string email = txtemail.Text;
string password = txtpass.Text;
string gender = rbgender.Text;
string nationality = ddcountry.Text;
string Connect_string = ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;
SqlConnection Connect = new SqlConnection(Connect_string);
Connect.Open();
string pass = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "MD5");
SqlCommand Command = new SqlCommand("INSERT INTO [Users] (username, firstname, lastname, email, password, gender, nationality) VALUES (#username, #firstname, #lastname, #email, #password, #gender, #nationality)", Connect);
Command.Parameters.AddWithValue("#username", username);
Command.Parameters.AddWithValue("#firstname", firstname);
Command.Parameters.AddWithValue("#lastname", lastname);
Command.Parameters.AddWithValue("#email", email);
Command.Parameters.AddWithValue("#password", pass);
Command.Parameters.AddWithValue("#gender", gender);
Command.Parameters.AddWithValue("#nationality", nationality);
Command.ExecuteNonQuery();
int success = Command.ExecuteNonQuery();
if (success > 0)
{
Label1.ForeColor = System.Drawing.ColorTranslator.FromHtml("#12223");
Label1.Visible = true;
Label1.Text = "You have successfully registered";
Connect.Close();
}
else
{
Label1.Text = "Your information has not been entered to database";
Connect.Close();
}
When I use
INSERT INTO Table () VALUE '"+textbox1.text +"'
it doesn't get duplicated but yeah, SQL injection-thingy.
You have two calls to the ExecuteNonQuery which actually fires the command:
Command.Parameters.AddWithValue("#nationality", nationality);
Command.ExecuteNonQuery(); //CALLED HERE First Time
int success = Command.ExecuteNonQuery(); //CALLED HERE Second Time (This is the one you want)
if (success > 0)
{
Label1.ForeColor = System.Drawing.ColorTranslator.FromHtml("#12223");
Label1.Visible = true;
Label1.Text = "You have successfully registered";
Connect.Close();
}
You are executing the query twice, by these lines:
Command.ExecuteNonQuery();
int success = Command.ExecuteNonQuery();
Remove the first Command.ExecuteNonQuery() and leave the second one with the int success.

Categories