ADO select statement with full text search with SQL injection - c#

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.

Related

Search sql server database server using Textbox and button in C#

So I am using MS visual studio to create an application in c# that will pull information from a sql server database.
I have created a textbox and a button to search my gridview. I am using a stored procedure that searched multiple rows to pull information from my Sql Database.
I am having trouble with my aspx.cs code. I have tried so many different ways to create a searchbox but haven't had any luck yet
Here is my code for my search button.
I am getting the error-
"Input string was not in a correct format."
this error is on the line cmd.ExecuteNonQuery();
Help is much appreciated, thank you.
protected void Button_srch_invest1_Click(object sender, EventArgs e)
{
string connectionStr = ConfigurationManager.ConnectionStrings["ORAProjectConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(connectionStr))
{
string find = "sp_SrcProtocols";
SqlCommand cmd = new SqlCommand(find, con);
cmd.Parameters.Add("#ORAID", SqlDbType.Int).Value = TextBox_Srch.Text;
cmd.Parameters.Add("#InvestLastName", SqlDbType.NVarChar).Value = TextBox_Srch.Text;
cmd.Parameters.Add("#ManagerLastName", SqlDbType.NVarChar).Value = TextBox_Srch.Text;
con.Open();
cmd.ExecuteNonQuery();
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
DataSet ds = new DataSet();
da.Fill(ds, "ORAID");
da.Fill(ds, "InvestLastName");
da.Fill(ds, "ManagerLastName");
GridView1.DataSource = ds;
GridView1.DataBind();
con.Close();
}
}
By default, a SqlCommand expects a query, not a stored procedure's name. You have to set the command type before executing it.
cmd.CommandType = CommandType.StoredProcedure;
It seems, you are passing same text box value (TextBox_Srch.Text) to all 3 parameters. And first parameter #ORAID is expecting integer value and you might be passing text. So it's causing SQL server to raise below error.
Input string was not in a correct format.
This is what worked (and i changed my sql to just accept one parameter #search)
protected void Button_srch_invest1_Click(object sender, EventArgs e)
{
string connectionStr = ConfigurationManager.ConnectionStrings["ORAProjectConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(connectionStr))
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "sp_SrcProtocols";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#search", SqlDbType.NVarChar).Value = TextBox_Srch.Text;
con.Open();
SqlDataReader rdr = cmd.ExecuteReader();
con.Close();
}
}

I have to show all the rows in my query - where's my mistake?

public Section SectionView(object id, SqlConnection conn)
{
using (SqlCommand cmd = new SqlCommand())
{
if (conn.State == ConnectionState.Closed)
conn.Open();
SqlDataAdapter sqlda = new SqlDataAdapter("TMR_SECTION_VIEW", conn);
SqlDataAdapter da = new SqlDataAdapter("data", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "TMR_SECTION_VIEW";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#sectionID", id.ToString);
cmd.Parameters.AddWithValue("#name", name);
da.SelectCommand = cmd;
DataTable dt = new DataTable();
DataTable dtbl = new DataTable();
sqlda.Fill(dtbl);
cmd.ExecuteNonQuery();
return id;
}
}
My stored procedure is:
ALTER PROCEDURE [dbo].[TMR_SECTION_VIEW]
#sectionID int, #name varchar(100)
AS
BEGIN
SELECT *
FROM Section
WHERE sectionid = #sectionID
END
You have things a little bit out of order...
You should be specifying the command name on the SqlCommand (not the DataAdapter) and you should be telling the DataAdapter to use the SqlCommand.
I'd change this to allow you to specify the Stored Procedure name as a parameter when you call the function:
public Section SectionView(object id, SqlConnection conn, string sql = String.Empty)
{
if (!String.IsNullOrEmpty(sql))
{
if (conn.State == ConnectionState.Closed) conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("#sectionID", id.ToString);
cmd.Parameters.AddWithValue("#name", name);
SqlDataAdapter da = new SqlDataAdapter
{ SelectCommand = cmd };
DataTable dtbl = new DataTable();
sqlda.Fill(dtbl);
return id;
}
}
}
You duplicated a lot of things (like setting the CommandType of your SqlCommand) and you created DataTable dt without using it, so I removed it from the sample in my answer.
So what's happening here is that you're specifying a sql string as a parameter (which can be a normal SQL query or a stored procedure) and you're building a SqlCommand with it that has parameters.
Using that SqlCommand, you're creating a DataAdapter having the SqlCommand as its SelectCommand and then you're using that DataAdapter to fill the DataTable.
NOTE: You don't need to execute SqlCommand.ExecuteNonQuery() when retrieving data as the DataAdapter.Fill() function basically does that for you.
ExecuteNonQuery would be useful when inserting or updating data - not when reading data.

Input on a stored sql procedure using C#

In sql I normally execute my procedure using
exec dbo.usp_FCS 'TIMV','serial'
And I tried something somewhat the same in c# but it seems I got this wrong
using (SqlConnection connection = new SqlConnection("Data Source=;Initial Catalog=;User ID=;Password="))
{
using (SqlCommand cmd = new SqlCommand("usp_FCS_GetUnitInfo_Takaya" + "'" + MachineName + " ','serial' " , connection))
{
try
{
connection.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
}
catch (SqlException ex)
{
label6.Visible = true;
label6.Text = string.Format("Failed to Access Database!\r\n\r\nError: {0}", ex.Message);
return;
}
}
}
My question is,how can I give those 2 inputs 'TIMV' and 'serial' of my stored procedure using c#?
Edit:
I tried something like this:
using (SqlCommand cmd = new SqlCommand("usp_FCS_GetUnitInfo_Takaya" , connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#p1", SqlDbType.VarChar).Value = MachineName;
cmd.Parameters.Add("#p2", SqlDbType.VarChar).Value = "serial";
try
{ my code...
And it is still not working
The most correct way to add a parameter to an SqlCommand is through the Add method that allows you to specify the datatype of the parameter and, in case of strings and decimals, the size and the precision of these values. In that way the Database Engine Optimizer can store your query for reuse and be a lot faster the second time you call it. In your case I would write
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#mname", SqlDbType.NVarChar, 20).Value = MachineName;
cmd.Parameters.Add("#serial", SqlDbType.NVarChar, 20).Value = "serial";
This assumes that your stored procedure receives two parameters named EXACTLY #mname and #serial, the type of the parameters is NVarChar and the length expected is 20 char. To give a more precise answer we need to see at least the first lines of the sp.
In your code above also the execution of the command is missing. Just creating the command does nothing until you execute it. Given the presence of an SqlDataAdapter I think you want to fill a DataSet or a DataTable and use this object as DataSource of your grid. Something like this
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
yourDataGrid.DataSource = dt;
And if this is an ASP.NET app, also the DataBind call
yourDataGrid.DataBind();
You use the Parameters collection of the SqlCommand class to send parameters to a stored procedure.
Suppose your parameter names are #p1 and #p2 (Please, for your sake, don't use names like this ever) - your c# code would look like this:
using (var cmd = new SqlCommand("usp_FCS_GetUnitInfo_Takaya", connection))
{
cmd..CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#p1", SqlDbType.VarChar).Value = MachineName;
cmd.Parameters.Add("#21", SqlDbType.VarChar).Value = "serial";
try
{
// rest of your code goes here....
Note: use the SqlDbType value that fits the parameters data type.
Try this:
DataSet ds = new DataSet("dts");
using (SqlConnection conn = new SqlConnection
("Data Source=;Initial Catalog=;User ID=;Password="))
{
try
{
SqlCommand sqlComm = new SqlCommand("usp_FCS_GetUnitInfo_Takaya",conn);
sqlComm.Parameters.AddWithValue("#p1", MachineName);
sqlComm.Parameters.AddWithValue("#p2", "serial");
sqlComm.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = sqlComm;
da.Fill(ds);
}
catch (Exception e)
{
label6.Visible = true;
label6.Text = string.Format
("Failed to Access Database!\r\n\r\nError: {0}", ex.Message);
return;
}

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

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

How use WHERE in SqlDataAdapter in C#

How use WHERE in SqlDataAdapter in C#?
I want get name in a textbox and use that at query but it wont work .
SqlConnection sqlconnection = new SqlConnection("Server=Behnam\\Accounting;Initial Catalog=Accounting;Integrated Security=TRUE");
DataTable dt = new DataTable();
string _search_name = txt_search.Text;
SqlDataAdapter SDA = new SqlDataAdapter("SELECT dbo.tbl_user.field1,dbo.tbl_user.field2 FROM tbl_user WHERE dbo.tbl_user.name=_search_name ", sqlconnection);
SDA.Fill(dt);
dataGridView1.DataSource = dt;
Prepare the command text and use a parameter for the value of your search.
Then use that command text to initialize a new SqlCommand. Fill the parameter value with AddWithValue and pass the SqlCommand to the constructor of the SqlDataAdapter.
string cmdText = "SELECT dbo.tbl_user.field1,dbo.tbl_user.field2 " +
"FROM tbl_user WHERE dbo.tbl_user.name=#search_name"
SqlCommand cmd = new SqlCommand(cmdText, sqlconnection);
cmd.Parameters.AddWithValue("#search_name", _search_name);
SqlDataAdapter SDA = new SqlDataAdapter(cmd);
The SqlDataAdapter will store your command as the SelectCommand property and will use the passed in SqlCommand to execute the query to retrieve the records from the database.
Keep in mind that AddWithValue is a shortcut with some drawbacks. For example it pass Always a string as a nvarchar parameter with size equal to the actual lenght of the variable. This effectively reduces the performance of the Sql Server Optimizer.
This is a very enlightening article on the issue
So, you were pretty close, you just needed to define a parameter inside the query and then add that parameter. However, in the following code block I've also conveniently recommended a more appropriate approach to using the classes needed to get the data (pun intended). The using statement here ensures that the objects get disposed of properly after you are done using them (man I just can't stop with the puns!)
using (SqlConnection c = new SqlConnection(connString))
{
c.Open();
using (SqlDataAdapter sda = new SqlDataAdapter(
"SELECT dbo.tbl_user.field1, dbo.tbl_user.field2 FROM tbl_user " +
"WHERE dbo.tbl_user.name= #name", c))
{
sda.SelectCommand.Parameters.AddWithValue("#name", txt_search.Text);
DataTable dt = new DataTable();
sda.Fill(dt);
}
}
Try this.
you were using the string directly in the query which will go undetected.
SqlConnection sqlconnection = new SqlConnection("Server=Behnam\\Accounting;
Initial Catalog=Accounting;Integrated Security=TRUE");
DataTable dt = new DataTable();
SqlDataAdapter SDA = new SqlDataAdapter("SELECT dbo.tbl_user.field1,dbo.tbl_user.field2 FROM tbl_user WHERE dbo.tbl_user.name=#searchName" , sqlconnection);
SDA.SelectCommand.Parameters.AddWithValue("#searchName", txt_search.Text);
SDA.Fill(dt);
dataGridView1.DataSource = dt;

Categories

Resources