New to C# and SQL - Why does my .AddWithValue not work? - c#

So currently I have this:
private void button1_Click(object sender, EventArgs e) {
string username = txtboxUsername.Text;
string password = txtboxPassword.Text;
string salt = string.Empty;
connection.Open();
MySqlCommand sql = new MySqlCommand("SELECT salts FROM users WHERE usernames = #username;", connection);
sql.Parameters.AddWithValue("#username", username);
using (MySqlDataReader reader = sql.ExecuteReader()) {
if (reader.HasRows) {
reader.Read();
salt = reader.GetString(0);
} else {
MessageBox.Show(sql.CommandText);
}
}
}
Now here is the issue, I don't get a compiler error when I run this, yet the sql.Parameters.AddWithValue( .. ); part doesn't actually add the string 'username' to the sql query. It simply leaves it at #username. Does anyone know what I am doing wrong here?

You forgot to call .Prepare().
MySqlCommand sql = new MySqlCommand("SELECT salts FROM users WHERE usernames = #username;", connection);
sql.Prepare(); // You forgot this *********************
sql.Parameters.AddWithValue("#username", username);
Below is an example using the proper resources with a using block:
using (MySqlConnection lconn = new MySqlConnection(connString))
{
lconn.Open();
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.Connection = lconn;
cmd.CommandText = "update " + activeTblName + " set bn=#bn where qId=#qId";
cmd.Prepare();
cmd.Parameters.AddWithValue("#qId", pqId);
cmd.Parameters.AddWithValue("#bn", ptheValue);
cmd.ExecuteNonQuery();
}
}
Tweak yours accordingly to clean up the resources automatically for you. MSDN shows examples of all of this.

Related

How to store multiple SQL data columns into different variables C#

I am trying to store sql data that I have for a voucher id and voucher amount into a variable and display it into a label on a click of a button.
protected void Button1_Click(object sender, EventArgs e)
{
string voucherId = String.Empty;
string voucherAmount = String.Empty;
string queryVoucherId = "select voucherid from ReturnForm where email = '" + Session["username"] + "';";
string queryVoucherAmount = "select voucheramount from ReturnForm where email = '" + Session["username"] + "';";
int index = 0;
using (SqlConnection con = new SqlConnection(str))
{
SqlCommand cmd = new SqlCommand(queryVoucherId, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
voucherId = reader[index].ToString();
index++;
}
}
using (SqlConnection con = new SqlConnection(str))
{
SqlCommand cmd = new SqlCommand(queryVoucherAmount, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
voucherAmount = reader[index].ToString();
index++;
}
}
if (txtVoucher.Text == voucherId)
{
Label3.Visible = true;
Label3.Text = voucherAmount;
}
}
When I click the button its giving me an error saying that the index is out of bounds.
Building on #JSGarcia's answer - but using parameters as one ALWAYS should - you'd get this code:
string email = Session['username'];
string query = $"SELECT voucherid, voucheramount FROM ReturnFrom WHERE Email = #email";
DataTable dt = new DataTable();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(query, conn))
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
// set the parameter before opening connection
// this also defines the type and length of parameter - just a guess here, might need to change this
cmd.Parameters.Add("#email", SqlDbType.VarChar, 100).Value = email;
conn.Open();
sda.Fill(dt);
conn.Close();
}
Personally, I'd rather use a data class like
public class VoucherData
{
public int Id { get; set; }
public Decimal Amount { get; set; }
}
and then get back a List<VoucherData> from your SQL query (using e.g. Dapper):
string query = $"SELECT Id, Amount FROM ReturnFrom WHERE Email = #email";
List<VoucherData> vouchers = conn.Query<VoucherData>(query).ToList();
I'd try to avoid the rather clunky and not very easy to use DataTable construct...
I strongly recommend combining your sql queries into a single one, write it into a datatable and continue your logic from there. IMHO it is much cleaner code:
string email = Session['username'];
string query = $"SELECT voucherid, voucheramount FROM ReturnFrom where Email = '{email}'";
DataTable dt = new DataTable();
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = conn.CreateCommand())
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
conn.Open();
sda.Fill(dt);
conn.Close();
}
// Work with DataTable dt from here on
...
Well, one more big tip?
You ONLY as a general rule need a dataadaptor if you going to update the data table.
And you ONLY need a new connection object if you say not using the sql command object.
The sqlcommand object has:
a connection object - no need to create a separate one
a reader - no need to create a separate one.
Note how I did NOT create a seperate connection object, but used the one built into the command object.
And since the parameter is the SAME in both cases? Then why not re-use that too!!
So, we get this:
void TestFun2()
{
String str = "some conneciton???";
DataTable rstVouch = new DataTable();
using (SqlCommand cmdSQL =
new SqlCommand("select voucherid from ReturnForm where email = #email",
new SqlConnection(str)))
{
cmdSQL.Parameters.Add("#email", SqlDbType.NVarChar).Value = Session["username"];
cmdSQL.Connection.Open();
rstVouch.Load(cmdSQL.ExecuteReader());
// now get vouch amount
cmdSQL.CommandText = "select voucheramount from ReturnForm where email = #email";
DataTable rstVouchAmount = new DataTable();
rstVouchAmount.Load(cmdSQL.ExecuteReader());
if (rstVouch.Rows[0]["vourcherid"].ToString() == txtVoucher.Text)
{
Label3.Visible = true;
Label3.Text = rstVouchAmount.Rows[0]["voucheramount"].ToString();
}
}
}

How to safely build MySqlConnection string from variables [duplicate]

So I've made a form where you login from a DB. Code should be self explanatory.
private void button1_Click(object sender, EventArgs e)
{
try
{
string MyConnection = "datasource=localhost;port=3306;username=root;password=xdmemes123";
MySqlConnection myConn = new MySqlConnection(MyConnection);
MySqlCommand SelectCommand = new MySqlCommand("select * from life.players where DBname='" + this.username.Text + "' and DBpass='" + this.password.Text +"' ; ", myConn);
MySqlDataReader myReader;
myConn.Open();
myReader = SelectCommand.ExecuteReader();
int count = 0;
while (myReader.Read())
{
count = count + 1;
}
if (count == 1)
{
Properties.Settings.Default.Security = "Secure";
Properties.Settings.Default.AdminName = username.Text;
Properties.Settings.Default.AdminPass = password.Text;
Properties.Settings.Default.Save();
MessageBox.Show("Logged in");
this.Hide();
Form2 f2 = new Form2();
f2.ShowDialog();
}
else if (count > 1)
{
Properties.Settings.Default.Security = "Insecure";
MessageBox.Show("Incorrect!");
}
else
{
Properties.Settings.Default.Security = "Insecure";
MessageBox.Show("Incorrect!");
myConn.Close();
}
}
catch (Exception ex)
{
MessageBox.Show("Something went wrong. Error copied to clipboard.");
Clipboard.SetText(ex.Message);
}
}
But my question is if this is safe from MYSQL Injections? And if not, what can I do to make it safe?
And if possible, write or explain how to write this code. I'm quite new to this coding but really do love it and would like to proceed on my program.
You can use Parameters.Add as inline text allows injection to occur, an example of better SQL is:
using (var conn = new SqlConnection( #"datasource=localhost;port=3306;username=root;password=xdmemes123"))
{
conn.Open();
var command = new SqlCommand("", conn);
command.CommandText = "select * from life.players where DBname='#sqlName' and DBpass='#sqlPass";
command.Parameters.Add("#sqlName", SqlDbType.VarChar ).Value = this.username.Text;
command.Parameters.Add("#sqlPass", SqlDbType.VarChar ).Value = this.password.Text;
using (SqlDataReader myReader = command.ExecuteReader())
{
while (myReader.Read())
{
string value = myReader["COLUMN NAME"].ToString();
}
}
}
In addition to the injection issue, you don't hash any of your passwords, I recommend looking into that.
The code is vulnerable to SQL injection, in fact, it's a perfect example - string concatenation and SELECT * would allow an attacker to input eg, a password of x' OR 1=1;# and retrieve all usernames and unencrypted passwords. Even the unnecessary loop to count for results will cause a noticeable delay that will tell the attacker he has succeded.
The following code isn't vulnerable to injection although it is NOT the proper way to authenticate passwords. It is for demonstration purposes only. Note that it doesn't useSELECT *, only a SELECT count(*):
//Reuse the same command with different connections
void InitializePlayerCmd()
{
var query = "SELECT COUNT(*) FROM life.players where DBName=#name and DbPass=#pass";
var myCmd= new MySqlCommand(query);
myCmd.Parameters.Add("#name", SqlDbType.VarChar,30 );
myCmd.Parameters.Add("#pass", SqlDbType.VarChar,200 );
_playerCheckCmd=myCmd;
}
//.....
int CheckPlayer(string someUserName, string someAlreadyHashedString)
{
var connectionString=Properties.Settings.Default.MyConnectionString;
using(var myConn= new MySqlConnection(connectionString))
{
_playerCheckCmd.Connection=myConn;
_playerCheckCmd.Parameters["#name"].Value=someUserName;
_playerCheckCmd.Parameters["#pass"].Value=someAlreadyHashedString;
myConn.Open();
var result=_playerCheckCmd.ExecuteScalar();
return result;
}
}

Parameterised QUERY in C# for simple login [duplicate]

This question already has answers here:
What are good ways to prevent SQL injection? [duplicate]
(4 answers)
Closed 4 years ago.
I have been doing simple website using ASP, but am not sure how to add parameterised query to avoid any SQL Injection attacks, can anybody help me to do it i always encounter errors and it has been more than a week that am doing and still i can't figured out. below i attached my simple code.
protected void btnLogin_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
string sql = "Select * From Users Where UserID='" + txtUser.Text + "' And Password='" + txtPwd.Text + "'";
con.Open();//opens the connection
//create the command object
cmd = new SqlCommand(sql, con);
//assigns the result to the reader
dr = cmd.ExecuteReader();
dr.Read();//read the record's data
//if there's a matching record found
if (dr.HasRows)
{
if (dr["UserType"].Equals("admin"))
{
Response.Redirect("dhome.aspx");
}
else if (dr["UserType"].Equals("staff"))
{
Response.Redirect("shome.aspx");
}
else if (dr["UserType"].Equals("member"))
{
Response.Redirect("mhome.aspx");
}
}
else
{
lblAlert.Text = "Invalid username or password!";
}
dr.Close(); //close the data reader
con.Close();//close the connection //declaration of data access components
}
You should add them using SqlCommand.Parameters.Add():
using (SqlConnection con = new SqlConnection(ConnectionString))
{
SqlCommand cmd = new SqlCommand("Select * From Users Where UserID=#username And Password=#password", con);
cmd.Parameters.Add("#username", SqlDbType.VarChar).Value = username;
cmd.Parameters.Add("#password", SqlDbType.VarChar).Value = password;
//rest of the code ...
}
You need to use SqlCommand.Parameters.Add. You should also implement dispose (via using blocks or calling Dispose) to release resources after use:
string connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sql = "Select * From Users Where UserID=#user And Password=#pwd";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#user", SqlDbType.VarChar);
command.Parameters["#user"].Value = "value";
command.Parameters.Add("#pwd", SqlDbType.VarChar);
command.Parameters["#pwd"].Value = "value";
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
// read row
}
}
}

c# System.InvalidOperationException: 'The connection is already open.'

I'm coding a Windows Forms login page for an administration application. My problem is, that when I try to log on, I get the error message
System.InvalidOperationException: 'The connection is already open.'
Any help would be appreciated
public partial class Form1 : Form
{
MySqlConnection con = new MySqlConnection (#"Database= app2000; Data Source = localhost; User = root; Password =''");
int i;
public Form1()
{
InitializeComponent();
}
private void btnClose_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void btnLogin_Click(object sender, EventArgs e)
{
i = 0;
con.Open();
MySqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM adminlogin WHERE username='" + txtBoxUsername + "'AND password='" + txtBoxPassword + "'";
cmd.ExecuteNonQuery();
DataTable dt = new DataTable();
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
da.Fill(dt);
i = Convert.ToInt32(dt.Rows.Count.ToString());
if (i == 0)
{
lblerrorInput.Show();
}
else
{
this.Hide();
Main ss = new Main();
ss.Show();
}
}
}
Do not cache Connection, it's a typical antipattern, but recreate it when you need it
public partial class Form1 : Form {
...
//DONE: Extract method
private static bool UserExists(string userName, string password) {
//DONE: Do not cache connections, but recreate them
using (MySqlConnection con = new MySqlConnection (#"...") {
con.Open();
//DONE: wrap IDisposable into using
using (MySqlCommand cmd = con.CreateCommand()) {
cmd.CommandType = CommandType.Text;
//DONE: Make query being readable
//DONE: Make query being parametrized
cmd.CommandText =
#"SELECT *
FROM adminlogin
WHERE username = #UserName
AND password = #PassWord"; // <- A-A-A! Password as a plain text!
//TODO: the simplest, but not the best solution:
// better to create parameters explicitly
// cmd.Parameters.Add(...)
cmd.Parameters.AddWithValue("#UserName", txtBoxUsername);
cmd.Parameters.AddWithValue("#PassWord", txtBoxPassword);
// If we have at least one record, the user exists
using (var reader = cmd.ExecuteReader()) {
return (reader.Read());
}
}
}
}
Finally
private void btnLogin_Click(object sender, EventArgs e) {
if (!UserExists(txtBoxUsername.Text, txtBoxPassword.Text))
lblerrorInput.Show();
else {
Hide();
Main ss = new Main();
ss.Show();
}
}
You forgot to close the connection, use con.Close() at the end to close the connection and avoid this error the next time the event fires.
There are some mistakes in your code.
You should close the sql connection when you finished your process.
I suggest you to use using statement to dispose connection instance after complete database actions.
Also, you should use command parameters to prevent Sql injection.
You can declare connection string like this;
private string _connectionString = #"Database= app2000; Data Source = localhost; User = root; Password =''";
The method part looks like;
using (var con = new MySqlConnection(_connectionString))
{
i = 0;
con.Open();
MySqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM adminlogin WHERE username = #username and password = #password";
cmd.Parameters.AddWithValue("#username", txtBoxUsername);
cmd.Parameters.AddWithValue("#password", txtBoxPassword);
cmd.ExecuteNonQuery();
DataTable dt = new DataTable();
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
da.Fill(dt);
i = Convert.ToInt32(dt.Rows.Count.ToString());
if (i == 0)
{
lblerrorInput.Show();
}
else
{
this.Hide();
Main ss = new Main();
ss.Show();
}
con.Close();
}
First, don't cache your Connection objects. It's a terrible practice and I've had to go back and fix it every time I accept a new job and inherit code. Most database access classes implement IDisposable, so use using and take advantage of it to keep your code clean. FYI, Readers and Adapters are also IDisposable so you can do the same with them, too.
string command = "select stuff from mydata";
string connection = GetConnectionStringFromEncryptedConfigFile();
using (var conn = new SqlConnection(connection))
{
using (var cmd = new SqlCommand(command, conn))
{
cmd.Connection.Open();
//do stuff
}
}
Second, if you're forced to use a cached connection (i.e., you inherited horrible code and don't have time to fix it yet), check your State first.
if(conn.State != System.Data.ConnectionState.Open)
{
conn.Open();
}
Note that there are a lot more states than just Open and Closed, and if you try to open a connection that is busy, you'll still get errors. It's still a much wiser approach to use the IDisposable implementations with using so you don't have to worry about this sort of thing so much.

How to Query Return Value on using Compact SQL Command?

I using a compact database created on visual studio. just for a stand alone system with it's database intact already although i'm stuck here in using a select query that could retrieve a boolean if the user exist on the database and also then return it's ID and Username if the user entry exist. can i ask for help regarding on this one.. I am a student trying to learn c# on using compact database.
private void btnLogin_Click(object sender, EventArgs e)
{
try
{
if (!IsEmpty())
{
if (!IsLenght())
{
using (SqlCeConnection con = new SqlCeConnection("Data Source=" +
System.IO.Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "INCdb.sdf")))
{
con.Open();
SqlCeCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT * FROM LoginTB Where username=#user1 AND password=#pass1";
cmd.Parameters.AddWithValue("#user1", UserTxt.Text.Trim());
cmd.Parameters.AddWithValue("#pass1", PassTxt.Text.Trim());
cmd.CommandType = CommandType.Text;
validlogin = (bool)cmd.ExecuteScalar();
con.Close();
MessageBox.Show(validlogin.ToString());
if (validlogin == true)
{
// cmd. return value ID
// cmd. return value Username
//SysMain Mn = new SysMain();
//Mn.ShowDialog();
//this.Hide();
}
}
}
}
}
catch (Exception ex)
{
gbf.msgBox(1, ex.Message.ToString(), "");
}
}
The code below is probably better, unless there is something special and unstated about the schema of LoginTB.
// ...
var validLogin = false;
using (SqlCeConnection con = new SqlCeConnection(
"Data Source=" +
System.IO.Path.Combine(
Path.GetDirectoryName(
System.Reflection.Assembly.GetEntryAssembly().Location),
"INCdb.sdf")))
{
con.Open();
SqlCeCommand cmd = con.CreateCommand();
cmd.CommandText =
"SELECT COUNT(*) FROM LoginTB Where username=#user1 AND password=#pass1";
cmd.Parameters.AddWithValue("#user1", UserTxt.Text.Trim());
cmd.Parameters.AddWithValue("#pass1", PassTxt.Text.Trim());
cmd.CommandType = CommandType.Text;
validlogin = ((int)cmd.ExecuteScalar()) > 0;
}
MessageBox.Show(validlogin.ToString());
// ...
Note the use of COUNT

Categories

Resources