Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
So I've been used to coding with try-catch-finally statements and not including the using statement and I'm trying to incorporate the latter into my code.
I've attached my original and revised code below. Is this revision sufficient?
Also, regarding catching for errors, I've seen the following code used a number of times on here. When should this be used/not used since this doesn't inform users about the error?
catch (Exception ex)
{
throw ex;
}
original code:
protected void signIn()
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
MySqlCommand comm;
comm = new MySqlCommand("Select user_id, username, email, salt, hashed_pw, role, activated FROM users WHERE username=#username", conn);
comm.Parameters.Add("#username", MySqlDbType.VarChar);
comm.Parameters["#username"].Value = txtUsername.Text;
MySqlDataReader reader;
try
{
conn.Open();
reader = comm.ExecuteReader();
if (reader.Read())
{
string saltAndPwd = String.Concat(txtPassword.Text, reader["salt"].ToString());
string hashSaltAndPwd = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPwd, "sha1");
if (hashSaltAndPwd.Equals(reader["hashed_pw"].ToString()))
{
if (reader["activated"].ToString().Equals("Y"))
{
Session["Username"] = reader["username"].ToString();
Session["Role"] = reader["role"].ToString();
Session["UserID"] = reader["user_id"].ToString();
Session["EmailAddress"] = reader["email"].ToString();
if (reader["role"].ToString().Equals("0"))
{
Session["PermanentRole"] = "admin";
}
else if (reader["role"].ToString().Equals("2"))
{
Session["PermanentRole"] = "tutor";
}
Response.Redirect("~/portal.aspx");
}
else
{
lblError.Text = "Your account has not been activated. Please check your inbox and activate your account or reset your password by clicking the link above.";
}
}
else
{
lblError.Text = "Incorrect password.";
}
}
else
{
lblError.Text = "Username does not exist.";
}
reader.Close();
}
catch
{
lblError.Text = "Database connection error. Please try again.";
}
finally
{
conn.Close();
}
}
revised code:
protected void signIn()
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using (MySqlConnection conn = new MySqlConnection(connStr))
{
using (MySqlCommand cmd = conn.CreateCommand())
{
string cmdText = "Select user_id, username, email, salt, hashed_pw, role, activated FROM users WHERE username=#username";
cmd.CommandText = cmdText;
cmd.Parameters.Add("#username", MySqlDbType.VarChar);
cmd.Parameters["#username"].Value = txtUsername.Text;
try
{
conn.Open();
reader = cmd.ExecuteReader();
if (reader.Read())
{
string saltAndPwd = String.Concat(txtPassword.Text, reader["salt"].ToString());
string hashSaltAndPwd = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPwd, "sha1");
if (hashSaltAndPwd.Equals(reader["hashed_pw"].ToString()))
{
if (reader["activated"].ToString().Equals("Y"))
{
Session["Username"] = reader["username"].ToString();
Session["Role"] = reader["role"].ToString();
Session["UserID"] = reader["user_id"].ToString();
Session["EmailAddress"] = reader["email"].ToString();
if (reader["role"].ToString().Equals("0"))
{
Session["PermanentRole"] = "admin";
}
else if (reader["role"].ToString().Equals("2"))
{
Session["PermanentRole"] = "tutor";
}
Response.Redirect("~/portal.aspx");
}
else
{
lblError.Text = "Your account has not been activated. Please check your inbox and activate your account or reset your password by clicking the link above.";
}
}
else
{
lblError.Text = "Incorrect password.";
}
}
else
{
lblError.Text = "Username does not exist.";
}
reader.Close();
}
catch
{
lblError.Text = "Database connection error. Please try again.";
}
finally
{
conn.Close();
}
}
}
1) conn.Close(); is not necessary since the using statement will call close for you. It is equivalent to
MySqlConnection conn = new MySqlConnection(connStr)
try
{
....
}
finally
{
conn.Close();
}
2) The catch with the form
catch (Exception ex)
{
throw ex;
}
is not recommended in any situation I can think of. It has 2 problems
It's doing nothing except rethrowing the exception. You don't catch the exception unless you want to do something with it (e.g.: logging the error)
Rethrowing the exception doing throw ex; cuts the stack trace. Anyone catching that exception will see the error as generated on that line, losing useful information
You don't need the finally { ...} because the using will Dispose the connection.
Your question about:
catch (Exception ex)
{
throw ex;
}
Is common when you want to Log the exception but still throw it, simply catching and re-throwing serves no purpose.
But should be done like this:
catch (Exception ex)
{
LogManager.Log(ex);
throw; //rethrow
}
Related
I am trying to add functionality to check the entered username and see if it exists in the MySql database before the user is successfully registered. I've tried looking at other similar questions and but because I lack the experience I cannot seem to implement it properly in my code.
Here's what I have so far:
private void button1_Click(object sender, EventArgs e)
{
string user = tbUser.Text;
string pass = tbPass.Text;
string email = tbEmail.Text;
if (tbUser.Text == "" || tbPass.Text == "" || tbEmail.Text == "")
{
MessageBox.Show("Please fill out all fields.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
bool exists = false;
string checkuser = $"SELECT COUNT(*) from users where name = {user}";
try
{
if (OpenConnection())
{
MySqlCommand cmd = new MySqlCommand(checkuser, conn);
try
{
cmd.Parameters.AddWithValue("name", tbUser.Text);
exists = (int)cmd.ExecuteScalar() > 0;
}
catch (Exception ex)
{
}
if (exists)
MessageBox.Show("Username already exists.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
{
Register(user, pass, email);
MessageBox.Show("Successfully Registered!");
this.Close();
}
}
}
catch (Exception ex)
{
}
}
}
public bool Register(string user, string pass, string email)
{
string register = $"INSERT INTO users (name, password, email) VALUES('{user}', '{pass}', '{email}');";
try
{
if (OpenConnection())
{
MySqlCommand cmd = new MySqlCommand(register, conn);
try
{
cmd.ExecuteNonQuery();
return true;
}
catch (Exception ex)
{
return false;
}
}
else
{
conn.Close();
return false;
}
}
catch (Exception ex)
{
conn.Close();
return false;
}
}
private bool OpenConnection()
{
try
{
conn.Open();
return true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Connection to the server failed.");
break;
case 1045:
MessageBox.Show("Database username or password is incorrect.");
break;
}
return false;
}
}
The above code doesn't work in registering the user & neither does it work in checking if the username exists. Would appreciate any help in pointing me in the right direction :)
The syntax, as far as I know, to declare a parameter in a command text isn't {user} but #user.
So this line of code of yours
string checkuser = $"SELECT COUNT(*) from users where name = {user}";
Should be
string checkuser = $"SELECT COUNT(*) from users where name = #user";
And the "#user" must correspond to the parameters name you are adding.
You falsly call the parameter name instead of user on this line
cmd.Parameters.AddWithValue("name", tbUser.Text);
So it should look like this
cmd.Parameters.AddWithValue("user", tbUser.Text);
As #Transcendent already mentioned in the comments in your Register method you never acutally add the 3 parameters used in the command text, to your parameters collections so those line are simply missing
cmd.Parameters.AddWithValue("user", tbUser.Text);
cmd.Parameters.AddWithValue("pass", tbPass.Text); //this line assumes there is a textbox called tbPass
cmd.Parameters.AddWithValue("email", tbEmail.Text); //this line assumes there is a textbox called tbEmail
I am Getting this Error (Not All Code Paths Return A Value). I want to insert data in my database with unique key constraint. but when i added this in my code my method is giving me this error.
Here is my code
public string Insert()
{
SqlConnection Conn = new SqlConnection(#"Data Source=ZARAK\SQLEXPRESS;Initial Catalog=ProjectDAL;integrated security=true");
try
{
Conn.Open();
SqlCommand cmd = new SqlCommand("Insert INTO tbl_User(Name,Email,Password) VALUES ('" + name + "','" + email + "','" + password + "')", Conn);
int restl = cmd.ExecuteNonQuery();
//temp = true;
return "Record Inserted successfully!";
}
catch (SqlException ex)
{
if (ex.Number == 2627)
{
return "Record Already Exists";
}
}
finally
{
Conn.Close();
}
}
Your problem is here:
catch (SqlException ex)
{
if (ex.Number == 2627)
{
return "Record Already Exists";
}
// **
}
If you look at the code paths of your application, each if also implicitly adds an else. In this case the else doesn't contain a return statement, hence the error.
And then there's exceptions...
Exceptions are there to handle exceptional cases. There's this implicit agreement amongst software developers that catch implies handle it appropriately.
One way to handle it is to inform the user that the record already exists (I'm guessing that's what you do). If another thing happens, it's not always productive to inform the user of the error; you might simply want to try again in a few seconds (deadlock) or do something else. Usually you handle code like that on a higher level, and let the exception ripple.
As a result, I cannot tell you what the code of ** needs to be; you need to decide that for yourself based on what you want to achieve.
For example:
catch (SqlException ex)
{
if (ex.Number == 2627)
{
return "Record Already Exists"; // user needs to do something
}
// We don't want to handle the rest here:
throw;
}
In your code The possible code paths are
=>Try=>finally=> Exit
=>catch=>ex.Number == 2627=>finally=>Exit
=>catch=>ex.Number != 2627=>finally=>Exit
Through your code you have handled the first two; The compiler will not know what to do if he met with the third Condition that's why it showing such error.
This can be solved by treating the third code path(ex.Number != 2627). Now consider the following code:
catch (SqlException ex)
{
if (ex.Number == 2627)
{
return "Record Already Exists";
}
return "Some other error occurred";
}
One more thing you have to notice is the Plain Text queries. Which
will opens a wide door for SQL Injection. So i request you to use
parameterized queries.
Including all these changes, the Method signature for the Insert() will be like the following:
public string Insert()
{
// Assuming Name email and passwords are global variables
// Or else need to get them
string conStr = #"Data Source=ZARAK\SQLEXPRESS;Initial Catalog=ProjectDAL;integrated security=true";
int queryResult = 0;
try
{
string querySQL = "Insert INTO tbl_User(Name,Email,Password)VALUES(#name,#email,#password)";
using (SqlConnection Conn = new SqlConnection(conStr))
{
using (SqlCommand cmd = new SqlCommand(querySQL, Conn))
{
cmd.Parameters.Add("#name", SqlDbType.VarChar).Value = Name;
cmd.Parameters.Add("#email", SqlDbType.VarChar).Value = email;
cmd.Parameters.Add("#password", SqlDbType.VarChar).Value = password;
queryResult= cmd.ExecuteNonQuery();
}
}
return queryResult + "Record/s Inserted successfully!";
}
catch (SqlException ex)
{
if (ex.Number == 2627)
{
return "Record Already Exists";
}
return "Some other error";
}
}
Alter your code into this to make sure that you have a return value.
public string Insert()
{
var result = String.Empty;
SqlConnection Conn = new SqlConnection(#"Data Source=ZARAK\SQLEXPRESS;Initial Catalog=ProjectDAL;integrated security=true");
try
{
Conn.Open();
SqlCommand cmd = new SqlCommand("Insert INTO tbl_User(Name,Email,Password) VALUES ('" + name + "','" + email + "','" + password + "')", Conn);
int restl = cmd.ExecuteNonQuery();
//temp = true;
result = "Record Inserted successfully!";
}
catch (SqlException ex)
{
if (ex.Number == 2627)
{
result = "Record Already Exists";
}
else {
result = ex.Message; // For other exceptions
}
}
finally
{
Conn.Close();
}
return result;
}
If your application throw an Exception and the Exception number is not equals to 2627, your method will not return a string value.
try
{
Conn.Open();
SqlCommand cmd = new SqlCommand("Insert INTO tbl_User(Name,Email,Password) VALUES ('" + name + "','" + email + "','" + password + "')", Conn);
int restl = cmd.ExecuteNonQuery();
//temp = true;
return "Record Inserted successfully!";
}
catch (SqlException ex)
{
if (ex.Number == 2627)
{
return "Record Already Exists";
}
return "Your Text";
}
finally
{
Conn.Close();
}
return "Your Text";
}
As the error states, you must return a string in all execution paths.
public string SomeMethod()
{
try
{
//Path 1
return "Path 1";
}
catch (SqlException ex)
{
if (...) {
//Path 2
return "Path 2";
}
//Path 3
//Return or rethrow.
//return "Path 3";
throw;
}
finally
{
//Clean Up Resources
}
}
In additional to atlaste's nice answer. In case of C# 6.0 in order to avoid such errors and simplify try .. catch block you can put exception filter:
try {
...
}
catch (SqlException ex) when (ex.Number == 2627) {
return "Record Already Exists";
}
no if, no throw;
Assuming that I call the method below with the right credentials:
private bool Connect(string username, string password)
{
string CONNSTRING = "Provider = MSDAORA; Data Source = ISDQA; User ID = {0}; Password = {1};";
OleDbConnection conn = new OleDbConnection();
string strCon = string.Format(CONNSTRING, username, password);
conn.ConnectionString = strCon;
bool isConnected = false;
try
{
conn.Open();
if (conn.State.ToString() == "Open")
isConnected = true;
}//try
catch (Exception ex)
{
lblErr.Text = "Connection error";
}//catch
finally
{
conn.Close();
}//finally
return isConnected;
}
I have successfully open the connection in my method below:
private bool ValidateUserCode(string usercode)
{
UserAccountDefine def = new UserAccountDefine();
UserAccountService srvc = new UserAccountService();
UserAccountObj obj = new UserAccountObj();
bool returnVal = false;
bool isValid = Connect(def.DB_DUMMY_USERCODE, def.DB_DUMMY_PASSWORD);
if (isValid)
{
obj.SQLQuery = string.Format(def.SQL_LOGIN, usercode.ToLower(), DateTime.Now.ToString("MM/dd/yyy"));
DataTable dt = srvc.Execute(obj, CRUD.READALL);
if (dt.Rows.Count == 1)
{
returnVal = true;
}
}
return returnVal;
}
The question is how can I determine the connection status in ValidateUserCode() method?
How can I close it afterwards?
Note:
I explicitly declare the string variables in UserAccountDefine(); so you don't have to worry about that.
I already tried declaring a new OleDbConnection conn inside the ValidateUserCode() to but the conn.State always returning "Closed".
UPDATE
I have a system with 2-layer security feature. 1st is in application and 2nd is on database. If a user logs in to the application, the username and password is also used to log him/her in to the database. Now, the scenario is when a user forgot his/her password, we can't determine the fullname, email and contact (which are maintained in the database) of the user. I just know his usercode. To determine the contact details, I have to open an active connection using a DUMMY_ACCOUNT.
Note that I never maintain the password inside the database.
First of all, you call Close() in your finally block, which means that at any point in your second method, the connection would be closed. Moreover, even if you don't Close() it,since conn is a local variable in Connect(), when you're back in ValidateUserCode(), the connection is already up for garbage collection, and when it's Dispose()d, it also closes automatically.
I sugges you either make it a member, pass it as an out parameter, return it by the Connect() method (and return null for failure, or something, if you don't like exceptions)..or redesign the code.
private OleDbConnection Connect(string username, string password)
{
string CONNSTRING = "Provider = MSDAORA; Data Source = ISDQA; User ID = {0}; Password = {1};";
OleDbConnection conn = new OleDbConnection();
string strCon = string.Format(CONNSTRING, username, password);
conn.ConnectionString = strCon;
try
{
conn.Open();
if (conn.State.ToString() == "Open")
return conn;
}//try
catch (Exception ex)
{
lblErr.Text = "Connection error";
}//catch
finally
{
//you don't want to close it here
//conn.Close();
}//finally
return null;
}
I am not sure how this information helps you.
I had similar problem while using OLEDB connection for Excel Reading. I didn't knew the answer. So, just I added a global variable for OleDbConnection initialized to null.
In my method, I used to check that null, if not close it and again open it.
if (con != null)
{
con.Close();
con.Dispose();
}
try
{
con = new OleDbConnection(connectionString);
}
catch (Exception ex)
{
MessageBox.Show("oledbConnection = " + ex.Message);
}
try
{
con.Open();
}
catch (Exception ex)
{
MessageBox.Show("connection open = " + ex.Message + "\n");
}
I could able to continue after this. You can try, if it works for you its good!
I'm not sure I follow the question quite right. My answer is based on the premise that you want to open/retrieve a connection, take an action, and close/release the connection afterward.
The code you include does not do that well. Typical DAO code resembles this pseudocode, in my case taken from some boilerplate code I use.
public DataSet FetchDataSet(string sql, IDictionary paramHash) {
var cnn = AcquireConnection();
var rtnDS = new DataSet();
try
{
var cmd = cnn.CreateCommand();
cmd.CommandText = sql;
SetParameters(cmd, paramHash);
IDbDataAdapter ida = new DataAdapter { SelectCommand = cmd };
LogSql(sql, paramHash, "FetchDataSet");
ida.Fill(rtnDS);
}
catch (Exception ex)
{
DebugWriteLn("Failed to get a value from the db.", ex);
throw;
}
finally
{
ReleaseConnection(cnn);
}
return rtnDS;
}
Note that the code above is strictly about communicating with the database. There is no assessment of whether the data is right or wrong. You might have a DAO that is a subclass of the one that contains the above code, and it might do this:
public MyItemType FindSomeValue(long Id)
{
const string sql = #"SELECT something from somewhere where id=:id";
var myParams = new Dictionary<string, long> { { "id", Id } };
var ds = FetchDataSet(sql, myParams);
return (from DataRow row in ds.Tables[0].Rows
select new Item
{
Id = Convert.ToInt64(row["ID"], CultureInfo.InvariantCulture),
Name = row["NAME"].ToString()
}).FirstOrDefault();
}
In fact, the above is pseudocode from a DAO implementation that I've used for years. It makes data access relatively painless. Note that there is some real code behind those methods like SetParameters (30 - 80 lines or so), and I have a bunch of other protected methods like FetchScalar, ExecuteSQL, etc.
i am using C# and i need to develop a check system for a mysql user and password.
So far what ive come up with is this and the error i get is that it is the wrong syntax...
public bool VerifyUser(string username, string password)
{
string returnValue = "";
string Query = "SELECT Pass FROM Base_Character WHERE User='" + username + "'";
MySqlCommand verifyUser = new MySqlCommand(Query, this.sqlConn);
try
{
verifyUser.ExecuteNonQuery();
MySqlDataReader myReader = verifyUser.ExecuteReader();
while (myReader.Read() != false)
{
returnValue = myReader.GetString(0);
}
myReader.Close();
}
catch (Exception excp)
{
Exception myExcp = new Exception("Could not verify user. Error: " +
excp.Message, excp);
throw (myExcp);
}
if (returnValue == password)
{
return false;
}
else
{
return true;
}
}
ExecuteNonQuery is for DELETE, INSERT and UPDATE. Whenever you want data returned as rows from database, use ExecuteReader
Your query should check the username and password together, if they exist in one record then the row is returned else nothing is returned.
You still need more to learn about coding/database programming using .Net
public bool VerifyUser(string username, string password)
{
bool returnValue = false;
string Query = "SELECT 1 FROM Base_Character WHERE User='" + username + "' AND pass='"+password+"'";
try
{
MySqlCommand command = new MySqlCommand(Query, this.sqlConn);
MySqlDataReader myReader = command.ExecuteReader();
if(myReader.Read())
{
returnValue = true;
}
myReader.Close();
}
catch (Exception excp)
{
throw;
}
return returnValue;
}
You should probably not throw a custom exception since you are using boolean
if(VerifyUser("user123", "******"))
{
//Congratulations
}
else
{
//Unable to log you in
}
Thanks guys, but this calls for a custom encryption that mysql cant hold or process, my main error was ovrlooking the executenonquery(), so i had to make the code like this:
if (AuthorizeTools.Encrypt.Password(Database.getPassword) != Password) //Password is already encrypted
Then set the mysql function to:
public string getPassword(string username)
{
string returnValue = "";
string Query = "SELECT Pass FROM Base_Character where (User=" +
"'" + username + "') LIMIT 1";
MySqlCommand checkUser = new MySqlCommand(Query, this.sqlConn);
try
{
checkUser.ExecuteNonQuery();
MySqlDataReader myReader = checkUser.ExecuteReader();
while (myReader.Read() != false)
{
returnValue = myReader.GetString(0);
}
myReader.Close();
}
catch (Exception excp)
{
Exception myExcp = new Exception("Could not grab password: " +
excp.Message, excp);
throw (myExcp);
}
return (returnValue);
}
I have an asp.net wizard control in my web application I am calling a stored procedure from code behind to insert data into database. Executing the proc in SSMS works fine and I had gotten this block to work once before and made changes (i unfortunately cannot remember which changes i made). My problem is that when the next button is clicked no errors are thrown and also no data is written to the database. I have tested by adding exception into the cnx2 try block and the exceptions were thrown so I know the code is executing to the place I want it to but it is still not inserting. Any help is appreciated Thank you. And please if there is any information i can add that may help let me know
protected void onNextButtonClick(object sender, EventArgs e)
{
if (Wizard1.ActiveStepIndex.Equals(1))
{
page1Submit();
}
else if (Wizard1.ActiveStepIndex.Equals(2))
{
page2Submit();
}
else if (Wizard1.ActiveStepIndex.Equals(3))
{
page3Submit();
}
else if (Wizard1.ActiveStepIndex.Equals(8))
{
page8submit();
}
}
protected void page1Submit()
{
string hispanic;
if (cbIsHispanic.Checked)
{
hispanic = "1";
}
else
{
hispanic = "0";
}
bool newReport = true;
SqlConnection cnx = new SqlConnection(server);
SqlCommand cmd = new SqlCommand("[ReportCheckExists]", cnx);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#reportNumber", dReportNumber.Text.ToString());
try
{
cnx.Open();
int rowCount = Convert.ToInt32(cmd.ExecuteScalar());
cnx.Close();
if (rowCount > 0)
{
newReport = false;
}
}
catch (Exception ex)
{
throw new Exception("Error executing MyProcedureName.", ex);
}
if (newReport)
{
SqlConnection cnx2 = new SqlConnection(server);
SqlCommand cmd2 = new SqlCommand("[NewReport]", cnx2);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Parameters.AddWithValue("#reportNumber", dReportNumber.Text.ToString());
try
{
cnx.Open();
cmd.ExecuteNonQuery();
cnx.Close();
}
catch (Exception ex)
{
throw new Exception("Error executing MyProcedureName.", ex);
}
}
else
{
string strJavaScript = "<script language = javascript type=text/Javascript> alert('That report number already exists. If you need to modify a report select it from the main menu or enter the report number again.')</script>";
this.Page.RegisterClientScriptBlock("Key4", strJavaScript);
Wizard1.ActiveStepIndex = 0;
}
}
It's probably because you are executing the cmd command, and not cmd2 in your second try catch block