How to Correctly Get data from MySQL Table C# - c#

I have a little problem with my codes. I'm trying to make my program faster, because it have too big delay, when i'm getting data from mysql and need to make my code faster. Can you help me about this code, is correctly to select * in table and is it good idea? Thank you! It's my code!
public bool GettingPlayers(ref clsConnection c)
{
try
{
MySqlConnection connect = new MySqlConnection(connectionMysql);
connect.Open();
MySqlCommand query = new MySqlCommand("SELECT * FROM Users Where Username='" + Escape(c.Username) + "'", connect);
query.Prepare();
MySqlDataReader dr = query.ExecuteReader();
if (dr.Read())
{
c.Username = dr[1].ToString();
c.Cash = double.Parse(dr[2].ToString());
c.TotalDistance = double.Parse(dr[3].ToString());
c.TotalHealth = double.Parse(dr[4].ToString());
c.Password = dr[5].ToString();
c.Status = int.Parse(dr[6].ToString());
c.IpAdress = dr[7].ToString();
c.TotalJobsDone = int.Parse(dr[8].ToString());
}
else
{
dr.Close();
connect.Close();
return false;
}
dr.Close();
connect.Close();
return true;
}
catch (Exception ex)
{
Form1 frm1 = new Form1();
frm1.LogTextToFile("sqlError", "GettingPlayers - " + ex);
return false;
}
}
Also I have a public string Escape(string str) => str.Replace("'", "\'").Replace(""", "\"");

You should avoid using the SELECT * in the query instead use the columns. I would suggest you use the stored procedure.
You are closing the connection twice it's unnecessary.
You should use the while loop in place of the if statement.
YOu can refer to the below code, I have not tested it but it will give you a good idea.
using (MySqlConnection connect = new MySqlConnection(connectionMysql))
{
connect.Open();
using (MySqlCommand query = new MySqlCommand("SELECT * FROM Users Where Username='" + Escape(c.Username) + "'", connect))
{
using (MySqlDataReader dr = query.ExecuteReader())
{
while (dr.Read())
{
c.Username = dr.GetString(1);
}
}
}
}
Few more suggestions.
Please use parameterized query to avoid the SQL injection, It will also improve the performance because the database can cache the execution plan.
you can use connection pooling instead of opening and closing the connections if you are making many calls.
you can use async/await to make the DB calls, this can improve the responsiveness of the application.

Related

C# reader.HasRows returns false all the time, even if I still have rows in the table

password = md5Crypt(password);
User u = null;
String sql = "SELECT * FROM user WHERE username='" + username + "' AND password='" + password + "'";
try
{
conn.Open();
MySqlCommand cmd = new MySqlCommand(sql, conn);
MySqlDataReader reader = cmd.ExecuteReader();
reader.Read();
Console.WriteLine(reader.Read());
if (reader.HasRows)
{
u = new User(reader["username"].ToString(), reader["password"].ToString(), reader["name"].ToString(), reader["role"].ToString());
}
else
{
u = null;
}
conn.Close();
}
catch (MySqlException e)
{
Console.WriteLine(e.Message);
conn.Close();
return null;
}
return u;
Never use string concatenatation to build your sql query. Instead use parameterized queries to prevent sql injection and other issues. That's the real issue.
But to fix your bug, you are calling MySqlDataReader.Read twice in a row. This will advance the reader to the next record. Instead do it only once:
if(reader.Read())
{
u = new User(reader["username"].ToString(), reader["password"].ToString(), reader["name"].ToString(), reader["role"].ToString());
}
else
{
u = null;
}
if(reader.Read())
{
// bug detected, two user with same name and password, log this/throw an exception
}
Also use the using statemennt (or try-catch-finally) for the connection to ensure that it gets disposed/closed everytime, even in case of an error.

SqlConnection in VS2015 C#

I am extremely new to C# web development (or any development for that matter) but I am trying to figure out how to save the results from a SQL query to a variable. I think I understand the process, but many of the examples I am finding on the Web use a SqlConnection statement. My copy of Visual Studio does not seem to have that command (pretty sure I am using the wrong word here). What am I missing either softwarewise or knowledgewise accomplish my task?
Thank you in advance for your help.
Dep
It depends on what you want to do: insert, update, get data. It also depends if you want to use an ORM library or not. I all depends. The code that I copy below is an example of how to retrieve a DataTable using Ado.Net (as you mentioned SqlConnection):
You have to use:
using System.Data;
using System.Data.SqlClient;
This is the code for retrieving a DataTable
private DataSet ExecuteDataset(string query)
{
var conn = new SqlConnection("Data Source=" + Server + ";Initial Catalog=" + Database + ";User Id=" + Username + ";Password=" + Password + ";");
DataSet ds;
try
{
conn.Open();
ds = new DataSet();
var da = new SqlDataAdapter(query, conn);
da.Fill(ds);
}
catch (Exception)
{
throw;
}
finally
{
conn.Dispose();
conn.Close();
}
return ds;
}
private DataSet ExecuteDataset(string query, SqlParameter[] parametros)
{
var conn = new SqlConnection("Data Source=" + Server + ";Initial Catalog=" + Database + ";User Id=" + Username + ";Password=" + Password + ";");
DataSet ds;
try
{
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = query;
foreach (SqlParameter p in parametros)
{
command.Parameters.Add(p);
}
ds = new DataSet();
var da = new SqlDataAdapter(command);
da.Fill(ds);
}
catch (Exception)
{
throw;
}
finally
{
conn.Dispose();
conn.Close();
}
return ds;
}
This is the code for running a query that does not expect result with and without parameters:
private void ExecuteNonQuery(string query)
{
var conn = new SqlConnection("Data Source=" + Server + ";Initial Catalog=" + Database + ";User Id=" + Username + ";Password=" + Password + ";");
try
{
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = query;
command.ExecuteNonQuery();
}
catch (Exception)
{
throw;
}
finally
{
conn.Dispose();
conn.Close();
}
}
private void ExecuteNonQuery(string query, SqlParameter[] parametros)
{
var conn = new SqlConnection("Data Source=" + Server + ";Initial Catalog=" + Database + ";User Id=" + Username + ";Password=" + Password + ";");
try
{
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = query;
foreach (SqlParameter p in parametros)
{
command.Parameters.Add(p);
}
command.ExecuteNonQuery();
}
catch (Exception)
{
throw;
}
finally
{
conn.Dispose();
conn.Close();
}
}
Here is the simplest example I can think of, take note of the using statements and comments
using System;
using System.Data;
using System.Data.SqlClient;
namespace DataAccess
{
class Program
{
static void Main(string[] args)
{
//Use your database details here.
var connString = #"Server=localhost\SQL2014;Database=AdventureWorks2012;Trusted_Connection=True;";
//Enter query here, ExecuteScalar returns first column first row only
//If you need to return more records use ExecuteReader/ExecuteNonQuery instead
var query = #"SELECT [AccountNumber]
FROM [Purchasing].[Vendor]
where Name = #Name";
string accountNumber = string.Empty;
//Using statement automatically closes the connection so you don't need to call conn.Close()
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(query, conn);
//Replace #Name as parameter to avoid dependency injection
cmd.Parameters.Add("#Name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = "Michael";
try
{
conn.Open();
//Cast the return value to the string, if it's an integer then use (int)
accountNumber = (string)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.WriteLine(accountNumber);
//ReadKey just to keep the console from closing
Console.ReadKey();
}
}
}
If you are really new to C# with SQL Server, I would recommend to start from scratch using one of the tutorials shown here. It provides a lot of information in a step-by-step manner:
The basics
Clearly definition of the core ceoncepts
How to setup dependencies to get started
How to choose between development models (code, model vs. database first)
How to write queries
and much more.
Using SqlConnection is a valid choice, but requires more effort in writing the queries for doing basic stuff like selecting, updating, deleting or inserting data. You actually have to construct the queries and take care to build and dispose the commands.
On a related note:
The new way of doing all database-related activities in C# or .NET would be to harness Entity Framework (EF), and try to move away from any ADO.NET-based code. The latter still exists and hasn't been marked as obsolete, though. You may want to use ADO.NET for small apps or for any PoC tasks. But, otherwise, EF is the way to go.
EF is an ORM, and is indeed built as a repository pattern and generates a conceptual layer for us to work with. All of the nuances of the connection and command are completely encapsulated from us. This way, we don't have to meddle with these bare-bones.
If you want to do it well, you have to edit a file named Web.config in your project and put something like this inside (with your own DB data):
<connectionStrings >
<add
name="myConnectionString"
connectionString="Server=myServerAddress;Database=myDataBase;User ID=myUsername;Password=myPassword;Trusted_Connection=False;"
providerName="System.Data.SqlClient"/>
</connectionStrings>
Then, in the code, you can use it with:
SqlConnection con = new SqlConnection(
WebConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString);
Finally you can do that you want with "con", for example:
string queryString = "SELECT name, surname FROM employees";
SqlCommand command = new SqlCommand(queryString, con);
con.Open();
SqlDataReader reader = command.ExecuteReader();
try
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader["name"], reader["surname"]));
}
}
finally
{
reader.Close();
}
i use this nuget library.
https://www.nuget.org/packages/SqlServerDB_dotNET/
using SqlServerDB;
string server = #"INSTANCE\SQLEXPRESS";
string database = "DEMODB";
string username = "sa";
string password = "";
string connectionString = #"Data Source="+ server + ";Initial Catalog="+ database + "; Trusted_Connection=True;User ID="+ username + ";Password="+ password + "";
DBConnection db_conn = new DBConnection(connectionString);
Console.WriteLine("IsConnected: " + db_conn.IsConnected());
if (db_conn == null || !db_conn.IsConnected())
{
Console.WriteLine("Connessione non valida.");
return;
}
string sql = "SELECT ID, Message FROM Logs ORDER BY IDLic;";
DataTable dtLogs = db_conn.SelectTable(sql);
if (dtLogs == null || dtLogs.Rows.Count == 0)
return;
// Loop with the foreach keyword.
foreach (DataRow dr in dtLogs.Rows)
{
Console.WriteLine("Message: " + dr["Message"].ToString().Trim());
}

Good prevention from MYSQL injection?

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;
}
}

returning true when the codition is false in c# rest

am trying to make a simple api for login in c# but my checking condition returns true even if the data is not present in database. here is my modellogin.cs
public string username { get; set; }
public string password { get; set; }
public string AddEmployees(Login Emp)
{
try
{
SqlDataReader reader = null;
SqlCommand com;
SqlConnection con = new SqlConnection(#"Data Source=DOTNET;Initial Catalog=edin;Integrated Security=True;Pooling=False");
com = new SqlCommand("Select count(*) from data where name='" + username + "' and phone='" + password + "'", con);
con.Open();
reader = com.ExecuteReader();
if (reader.Read())
{
return "success";//returns this always
}
else
{
return "error";
}
con.Close();
}
catch (Exception aa)
{
return aa.ToString();
}
}
and my Controller
public string AddEmployees(Login Emp)
{
Login employe = new Login();
var response = employe.AddEmployees(Emp);
return response;
}
where am wrong..? or am i missing some code ..can anyone help
If you were trying to select the actual rows themselves, that code would probably behave as you expect, returning true if rows were found or false otherwise.
You're doing a Select count(*) though, which is going to return 0 if no matching records were found, so there's always something returned.
Try using ExecuteScalar() instead of ExecuteReader. It'll return your single value (the row count), which you can use to determine success or failure.
int rowCount = com.ExecuteScalar();
return (rowCount == 0) ? "failure" : "success";
dont use count. select a field instead. HasRows() will help what you are looking for. try this:
SqlDataReader reader = null;
SqlCommand com;
SqlConnection con = new SqlConnection(#"Data Source=DOTNET;Initial Catalog=edin;Integrated Security=True;Pooling=False");
com = new SqlCommand("Select name from data where name='" + username + "' and phone='" + password + "'", con);
con.Open();
reader = com.ExecuteReader();
return reader.HasRows() ? "success" : "error";
con.Close();
You have:
Select count(*) from data where name= ...
so you will always have result , even if specified user doesn't exists in db. So you will always get reader.Read() true.
On the other hand i don't thing that returning string as operation result is good choice. And remember to avoid concatenation in sql query. Rather that use sql parameters , because this kind of creating query:
Select count(*) from data where name='" + username + "' and phone='" + password + "'"
is very risky, because of sql injection.

Equivalent C# of this PHP code

Trying to learn C# and I can't quite get a handle on querying and getting results. I'm trying to figure out both how to and the best way of doing the below in C# .NET. It's a MySql database.
//Interact with the DB. Find out if this hashed account #'s in there.
$dbh = $this->getPDO();
$procedure = "SELECT userPass FROM 499Users WHERE accName = :acc";
$call = $dbh->prepare($procedure);
$call->bindParam(':acc', $testAcc, PDO::PARAM_STR);
$call->execute();
//Fetch up to 1 result row
$row = $call->fetch(PDO::FETCH_ASSOC);
This is my latest try: Also I realize I should probably be using parameters, but I just want it to work first
MySqlConnectionStringBuilder conn_string = new MySqlConnectionStringBuilder();
conn_string.Server = "*";
conn_string.UserID = "*";
conn_string.Password = "*";
conn_string.Database = "*";
conn_string.Port = 3306;
MySqlConnection connection = new MySqlConnection(conn_string.ToString());
try
{
Console.WriteLine("Trying to connect to: ..." + conn_string); Console.WriteLine("Connecting to MySQL...");
connection.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
string hashedAcc = this.HashPassword(acc);
//Verify hashed account
string query = "SELECT userPass FROM 49Users WHERE accName =" + hashedAcc;
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader myReader;
myReader = cmd.ExecuteReader();
try
{
while (myReader.Read())
{
Console.WriteLine(myReader.GetString(0));
}
}
finally
{
myReader.Close();
connection.Close();
}
The following WHERE clause:
WHERE accName =" + hashedAcc;
will cause an error if accName is not of type int, it needs quotes around it.
You should use parameterized query just like you did in PDO, it avoid errors like this and SQL injections as well.
var query = "SELECT userPass FROM 49Users WHERE accName = #hashedAcc";
var cmd = new MySqlCommand(query, connection);
cmd.Parameters.AddWithValue("#hashedAcc", hashedAcc);

Categories