Best way to debug parameterized query in c# [duplicate] - c#

This question already has answers here:
Get the generated SQL statement from a SqlCommand object?
(25 answers)
Closed 6 years ago.
Escape ( ' ) symbol in Textbox for asp.net c#
Based on the question in post above, most people suggested that "parameterized query" is the best solution to avoid the sql injection.
Below is my code by using the sql injection
public DataSet checkemp(string user)
{
strsql = "SELECT * from employee where employeeid = #userid";
SqlConnection con = new SqlConnection(connectionString);
SqlDataAdapter da = new SqlDataAdapter(strsql, connectionString);
da.SelectCommand.Parameters.Add("#userid", SqlDbType.VarChar, 50).Value = user;
// pretend the user name is "Micheal"
con.Open();
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
con.Dispose();
return ds;
}
During the debugging, I can only get the query "SELECT * from employee where employeeid = #userid" if I point on "strsql" label, but not "SELECT * from employee where employeeid = 'Micheal'.
Any solution suggested to solve this question and make it most efficiency? thanks everyone!

I would introduce an extension method (although this is not must, actual logic is more important) that returns the parsed query as below, and call that only during debug mode:
public void TestMethod()
{
string cmdStr = "<some sql command text>";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(cmdStr, con);
cmd.Parameters.AddWithValue("<param1>", <value1>); // add parameter in any way you want
#if DEBUG
string parsedQuery = cmd.GetParsedQuery();
Console.WriteLine(parsedQuery); // or whatever
#endif
SqlDataAdapter da = new SqlDataAdapter(cmd);
con.Open();
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
con.Dispose();
return ds;
}
public static string GetParsedQuery(this SqlCommand cmd)
{
if(cmd.CommandType == CommandType.Text)
{
string parsedQuery = cmd.CommandText;
foreach(var p in cmd.Parameters)
{
parsedQuery = parsedQuery.Replace(p.ParameterName, Convert.ToString(p.Value));
}
return parsedQuery;
}
return null;
}
Note that, although I have directly written extension method (for brevity), it should really be defined in a separate static class.

Try MiniProfiler :
"An ADO.NET profiler, capable of profiling calls on raw ADO.NET"
http://miniprofiler.com/
public DataSet checkemp(string user)
{
strsql = "SELECT * from employee where employeeid = #userid";
SqlConnection con = GetOpenConnection(connectionString);
SqlDataAdapter da = new SqlDataAdapter(strsql, connectionString);
da.SelectCommand.Parameters.Add("#userid", SqlDbType.VarChar, 50).Value = user;
// pretend the user name is "Micheal"
con.Open();
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
con.Dispose();
return ds;
}
public static DbConnection GetOpenConnection(string connectionString)
{
var cnn = new SqlConnection(connectionString);
// wrap the connection with a profiling connection that tracks timings
return new StackExchange.Profiling.Data.ProfiledDbConnection(cnn, MiniProfiler.Current);
}
** You might need to wrap SqlCommand with ProfiledDbCommand

Related

How to Reuse Logic Without Copy/Pasting Blocks of Code - C#

My project reuses the code below multiple times with only a few variables changing. I've noted the values that change with e.g. ***value***.
if (comboBox1.Text == ***"Most recent first"***)
{
string dgvconn = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\n0740572\Projects\CW\CW\bin\Debug\Database1.mdf;Integrated Security=True";
string sql = "select * from Records where UserID = #userID Order By ***Date Desc***";
SqlConnection connection = new SqlConnection(dgvconn);
SqlDataAdapter dataadapter = new SqlDataAdapter(sql, connection);
dataadapter.SelectCommand.Parameters.AddWithValue("#userID", currentUserID);
DataSet ds = new DataSet();
connection.Open();
dataadapter.Fill(ds, "Records");
connection.Close();
recordsDataGridView.DataSource = ds;
recordsDataGridView.DataMember = "Records";
}
How can I use this same logic, with different values, without copying and pasting the if statement multiple times?
Sounds to me you want something like:
private void foo(string matchText, string sortBy) {
if (comboBox1.Text == matchText)
{
string dgvconn = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\n0740572\Projects\CW\CW\bin\Debug\Database1.mdf;Integrated Security=True";
string sql = "select * from Records where UserID = #userID Order By " + sortBy;
SqlConnection connection = new SqlConnection(dgvconn);
SqlDataAdapter dataadapter = new SqlDataAdapter(sql, connection);
dataadapter.SelectCommand.Parameters.AddWithValue("#userID", currentUserID);
DataSet ds = new DataSet();
connection.Open();
dataadapter.Fill(ds, "Records");
connection.Close();
recordsDataGridView.DataSource = ds;
recordsDataGridView.DataMember = "Records";
}
}//foo
//Call the method
foo("Most recent first", "Date DESC");
foo("Most recent last", "Date");
foo("By Username", "User");

passing a parameter to GridView when calling data from database

so my GridView Returns all the data in my Table but i want to return data that are related to the UserName attribute in the table,mind you that i have Multiple UserName's in the table.
i tried giving my function a string username and in my page_load:
string SessionName;
protected void Page_Load(object sender, EventArgs e)
{
SessionName = Session["Username"].ToString();
DataSet ds = InsertClass.GetCart(SessionName);
}
in my class:
public static DataSet GetCart(string UserName)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connectionString"].ToString());
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM [ShoppingCart] WHERE UserName = #UserName ", conn);
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("#UserName", UserName));
DataSet ds = new DataSet();
SqlDataAdapter adapter1 = new SqlDataAdapter(cmd);
adapter1.Fill(ds);
conn.Close();
return ds;
}
Edit:my mistake guys i didnt add the parameter to my function because i was trying alot of things before i asked the question and forgot to put it back.
You are not passing username as string parameter here in your code public static DataSet GetCart()
Here is correct one:
public static DataSet GetCart(string userName)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connectionString"].ToString());
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM [ShoppingCart] WHERE UserName = #UserName ", conn);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#UserName", userName);
DataSet ds = new DataSet();
SqlDataAdapter adapter1 = new SqlDataAdapter(cmd);
adapter1.Fill(ds);
conn.Close();
return ds;
}
So in your page_load you are calling your GetCart function with parameter SessionName, but i cannot see your GetCart function is taking any parameter:
DataSet ds = InsertClass.GetCart(SessionName);
public static DataSet GetCart()
{.....}
And what is the reference of UserName, when you add the parameter to sql query:
cmd.Parameters.Add(new SqlParameter("#UserName", UserName));
Did you debug and see that you are passing the right parameter ?

ADO select statement with full text search with SQL injection

The database that I am connecting to has a table with a Full Text Search index. This works correctly.
select * from MyTable where contains(*, 'value')
In WPF if I send that exact command down it works. However value is not hard coded it is something an user types in so it needs to be protected for SQL injection. The issue is that in doing so it does not return results. Here is my code;
DataTable dt = new DataTable();
string ConString = "Data Source=127.0.0.1,1433;Initial Catalog=MyDB;User Id=sa;Password=amazingSecurePassword;";
using (SqlConnection con = new SqlConnection(ConString))
{
string sqlCMD = "select * from MyTable where contains(*, #s1)"
SqlCommand cmd = new SqlCommand(sqlCMD, con);
SqlDataAdapter da = new SqlDataAdapter();
try
{
con.Open();
cmd = new SqlCommand(sqlCMD, con);
cmd.Parameters.Add(new SqlParameter("#s1", "value"));
da.SelectCommand = cmd;
da.Fill(dt);
con.Close();
}
catch (Exception x)
{
//Error logic
}
finally
{
cmd.Dispose();
con.Close();
}
}
Edit: #Mike comment worked. Change the SqlDbType.NVarChar fixed the issue
As noted in the above comment, setting the SQlDbType to NVarChar during the creation of the SqlParameter helps the CLR determine the right data type. More info about the SqlParameter constructor at MSDN.

Prepared SELECT statement in .Net

I can't understand what I am doing wrong, I can't seem to SELECT with a prepared statement. However I can INSERT with a prepared statement.
MySqlCommand cmd = new MySqlCommand("SELECT * FROM code_post WHERE name = ?postRequired LIMIT 1", dbcon);
cmd.Parameters.Add(new MySqlParameter("?postRequired", requestString));
cmd.ExecuteNonQuery();
DataSet ds = new DataSet();
cmd.fill(ds, "result");
try {
thisBlog = ds.Tables["result"].Rows[0];
} catch {
invalid();
return;
}
Any advice on this would be greatly appreciated!
To fill a DataSet you will need a DataAdapter.
Try this:
MySqlCommand cmd = new MySqlCommand("SELECT * FROM code_post WHERE name = ?postRequired LIMIT 1", dbcon);
cmd.Parameters.Add(new MySqlParameter("?postRequired", requestString));
cmd.ExecuteNonQuery();
DataSet ds = new DataSet();
MySqlDataAdapter dAdap = new MySqlDataAdapter();
dAdap.SelectCommand = cmd;
dAdap.Fill(ds, "result");
try {
thisBlog = ds.Tables["result"].Rows[0];
} catch {
invalid();
return;
}
You need to use SqlDataAdapter
DataAdapter represents a set of data commands and a database connection that are used to fill the DataSet and update a SQL Server database.
The SqlDataAdapter provides this bridge by mapping Fill, which changes the data in the DataSet to match the data in the data source
Check the following syntax:
private static DataSet SelectRows(DataSet dataset,
string connectionString,string queryString)
{
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(
queryString, connection);
adapter.Fill(dataset);
return dataset;
}
}

Read SQL Table into C# DataTable

I've read a lot of posts about inserting a DataTable into a SQL table, but is there an easy way to pull a SQL table into a .NET DataTable?
Here, give this a shot (this is just a pseudocode)
using System;
using System.Data;
using System.Data.SqlClient;
public class PullDataTest
{
// your data table
private DataTable dataTable = new DataTable();
public PullDataTest()
{
}
// your method to pull data from database to datatable
public void PullData()
{
string connString = #"your connection string here";
string query = "select * from table";
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
// create data adapter
SqlDataAdapter da = new SqlDataAdapter(cmd);
// this will query your database and return the result to your datatable
da.Fill(dataTable);
conn.Close();
da.Dispose();
}
}
var table = new DataTable();
using (var da = new SqlDataAdapter("SELECT * FROM mytable", "connection string"))
{
da.Fill(table);
}
Lots of ways.
Use ADO.Net and use fill on the data adapter to get a DataTable:
using (SqlDataAdapter dataAdapter
= new SqlDataAdapter ("SELECT blah FROM blahblah ", sqlConn))
{
// create the DataSet
DataSet dataSet = new DataSet();
// fill the DataSet using our DataAdapter
dataAdapter.Fill (dataSet);
}
You can then get the data table out of the dataset.
Note in the upvoted answer dataset isn't used, (It appeared after my answer)
It does
// create data adapter
SqlDataAdapter da = new SqlDataAdapter(cmd);
// this will query your database and return the result to your datatable
da.Fill(dataTable);
Which is preferable to mine.
I would strongly recommend looking at entity framework though ... using datatables and datasets isn't a great idea. There is no type safety on them which means debugging can only be done at run time. With strongly typed collections (that you can get from using LINQ2SQL or entity framework) your life will be a lot easier.
Edit: Perhaps I wasn't clear: Datatables = good, datasets = evil. If you are using ADO.Net then you can use both of these technologies (EF, linq2sql, dapper, nhibernate, orm of the month) as they generally sit on top of ado.net. The advantage you get is that you can update your model far easier as your schema changes provided you have the right level of abstraction by levering code generation.
The ado.net adapter uses providers that expose the type info of the database, for instance by default it uses a sql server provider, you can also plug in - for instance - devart postgress provider and still get access to the type info which will then allow you to as above use your orm of choice (almost painlessly - there are a few quirks) - i believe Microsoft also provide an oracle provider. The ENTIRE purpose of this is to abstract away from the database implementation where possible.
Vendor independent version, solely relies on ADO.NET interfaces; 2 ways:
public DataTable Read1<T>(string query) where T : IDbConnection, new()
{
using (var conn = new T())
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.Connection.ConnectionString = _connectionString;
cmd.Connection.Open();
var table = new DataTable();
table.Load(cmd.ExecuteReader());
return table;
}
}
}
public DataTable Read2<S, T>(string query) where S : IDbConnection, new()
where T : IDbDataAdapter, IDisposable, new()
{
using (var conn = new S())
{
using (var da = new T())
{
using (da.SelectCommand = conn.CreateCommand())
{
da.SelectCommand.CommandText = query;
da.SelectCommand.Connection.ConnectionString = _connectionString;
DataSet ds = new DataSet(); //conn is opened by dataadapter
da.Fill(ds);
return ds.Tables[0];
}
}
}
}
I did some performance testing, and the second approach always outperformed the first.
Stopwatch sw = Stopwatch.StartNew();
DataTable dt = null;
for (int i = 0; i < 100; i++)
{
dt = Read1<MySqlConnection>(query); // ~9800ms
dt = Read2<MySqlConnection, MySqlDataAdapter>(query); // ~2300ms
dt = Read1<SQLiteConnection>(query); // ~4000ms
dt = Read2<SQLiteConnection, SQLiteDataAdapter>(query); // ~2000ms
dt = Read1<SqlCeConnection>(query); // ~5700ms
dt = Read2<SqlCeConnection, SqlCeDataAdapter>(query); // ~5700ms
dt = Read1<SqlConnection>(query); // ~850ms
dt = Read2<SqlConnection, SqlDataAdapter>(query); // ~600ms
dt = Read1<VistaDBConnection>(query); // ~3900ms
dt = Read2<VistaDBConnection, VistaDBDataAdapter>(query); // ~3700ms
}
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());
Read1 looks better on eyes, but data adapter performs better (not to confuse that one db outperformed the other, the queries were all different). The difference between the two depended on query though. The reason could be that Load requires various constraints to be checked row by row from the documentation when adding rows (its a method on DataTable) while Fill is on DataAdapters which were designed just for that - fast creation of DataTables.
Centerlized Model: You can use it from any where!
You just need to call Below Format From your function to this class
DataSet ds = new DataSet();
SqlParameter[] p = new SqlParameter[1];
string Query = "Describe Query Information/either sp, text or TableDirect";
DbConnectionHelper dbh = new DbConnectionHelper ();
ds = dbh. DBConnection("Here you use your Table Name", p , string Query, CommandType.StoredProcedure);
That's it. it's perfect method.
public class DbConnectionHelper {
public DataSet DBConnection(string TableName, SqlParameter[] p, string Query, CommandType cmdText) {
string connString = # "your connection string here";
//Object Declaration
DataSet ds = new DataSet();
SqlConnection con = new SqlConnection();
SqlCommand cmd = new SqlCommand();
SqlDataAdapter sda = new SqlDataAdapter();
try {
//Get Connection string and Make Connection
con.ConnectionString = connString; //Get the Connection String
if (con.State == ConnectionState.Closed) {
con.Open(); //Connection Open
}
if (cmdText == CommandType.StoredProcedure) //Type : Stored Procedure
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = Query;
if (p.Length > 0) // If Any parameter is there means, we need to add.
{
for (int i = 0; i < p.Length; i++) {
cmd.Parameters.Add(p[i]);
}
}
}
if (cmdText == CommandType.Text) // Type : Text
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = Query;
}
if (cmdText == CommandType.TableDirect) //Type: Table Direct
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = Query;
}
cmd.Connection = con; //Get Connection in Command
sda.SelectCommand = cmd; // Select Command From Command to SqlDataAdaptor
sda.Fill(ds, TableName); // Execute Query and Get Result into DataSet
con.Close(); //Connection Close
} catch (Exception ex) {
throw ex; //Here you need to handle Exception
}
return ds;
}
}

Categories

Resources