Okay I am a noob to parameterized queries. I understand why you should use them and all but I cannot find any resource that shows the correct way or at least one that shows the correct way that actually works.
So my question is about whether or not my code is right. It compiles and runs just fine but it returns absolutely nothing in the gridview.
protected void SearchButton_Click(object sender, EventArgs e)
{
string searchBoxValue = SearchBox.Text;
string columnNameValue = ColumnName.SelectedValue;
columnNameValue.ToLower();
SqlCommand searchCommand = new SqlCommand();
searchCommand.Connection = connection;
searchCommand.CommandText = "select firstname AS FirstName,lastname AS LastName, zipcode as ZipCode, phone AS Phone, email AS Email, cancersurvivor AS CancerSurvivor, ethnicity AS Ethnicity from registrants where #columnname = #searchterm";
SqlParameter columnParam = new SqlParameter();
columnParam.ParameterName = "#columnname";
columnParam.Value = columnNameValue;
SqlParameter searchBoxParam = new SqlParameter();
searchBoxParam.ParameterName = "#searchterm";
searchBoxParam.Value = searchBoxValue;
searchCommand.Parameters.Add(columnParam);
searchCommand.Parameters.Add(searchBoxParam);
UpdateTable(searchCommand);
}
The UpdateTable function takes in the an SqlCommand object and then uses a DataAdapter object to execute the command and fills a DataTable object then sets the gridview datasource to the datatable object and binds it.
Like I said before I am really looking for the proper way to do this? do I need a stored procedure in order to do this? I am confused by all this and why it is not working.
You cannot parameterise #columnname. This needs to be a literal in your query.
Your statement
select
/* .... */
from registrants where #columnname = #searchterm
will return all rows from registrants if the value of the parameters happens to be the same or no rows otherwise.
It will not look and see if you have a column of that name and see if #searchterm exists in it.
To do this in a safe way you would need to check that columnNameValue matches one of a whitelist of valid column names (as you must know the possible column names in that table) and concatenate it into your query. Do not concatenate unvalidated user input. as then you open yourself up to SQL injection.
So you might implement it something like
using System.Linq;
protected void SearchButton_Click(object sender, EventArgs e)
{
string columnNameValue = ColumnName.SelectedValue.ToLower();
var validColumnNames = new string[] { "firstname", "lastname", "zipcode" };
if (!validColumnNames.Contains(columnNameValue))
{
throw new Exception("Unexpected column name " + columnNameValue);
}
/* ... code omitted */
searchCommand.CommandText = "select firstname AS FirstName,lastname AS LastName, zipcode as ZipCode, phone AS Phone, email AS Email, cancersurvivor AS CancerSurvivor, ethnicity AS Ethnicity from registrants where " + columnNameValue + " = #searchterm";
/* ... code omitted */
}
The purpose of paramtrized command are to prevent sql injection. You cannot parametrize the name of the column, sql will take it as a string.
protected void SearchButton_Click(object sender, EventArgs e)
{
string searchBoxValue = SearchBox.Text;
string columnNameValue = ColumnName.SelectedValue;
columnNameValue.ToLower();
SqlCommand searchCommand = new SqlCommand();
searchCommand.Connection = connection;
//Put the column name directly in the request, but use a parameter for the search value
searchCommand.CommandText = "select firstname AS FirstName,lastname AS LastName, zipcode as ZipCode, phone AS Phone, email AS Email, cancersurvivor AS CancerSurvivor, ethnicity AS Ethnicity from registrants where " + columnNameValue + " = #searchterm";
/* No need for this part
SqlParameter columnParam = new SqlParameter();
columnParam.ParameterName = "#columnname";
columnParam.Value = columnNameValue;
*/
SqlParameter searchBoxParam = new SqlParameter();
searchBoxParam.ParameterName = "#searchterm";
searchBoxParam.Value = searchBoxValue;
//searchCommand.Parameters.Add(columnParam);
searchCommand.Parameters.Add(searchBoxParam);
UpdateTable(searchCommand);
}
Your issue is in how you're trying to make your column name as a parameter. You'll want to change the query as a whole to reflect which column you want to filter by. Try the following:
protected void SearchButton_Click(object sender, EventArgs e)
{
string searchBoxValue = SearchBox.Text;
string columnNameValue = ColumnName.SelectedValue;
columnNameValue.ToLower();
SqlCommand searchCommand = new SqlCommand();
searchCommand.Connection = connection;
searchCommand.CommandText = String.Format("select firstname AS FirstName,lastname AS LastName, zipcode as ZipCode, phone AS Phone, email AS Email, cancersurvivor AS CancerSurvivor, ethnicity AS Ethnicity from registrants where {0} = #searchterm",columnNameValue);
SqlParameter searchBoxParam = new SqlParameter();
searchBoxParam.ParameterName = "#searchterm";
searchBoxParam.Value = searchBoxValue;
searchCommand.Parameters.Add(columnParam);
searchCommand.Parameters.Add(searchBoxParam);
UpdateTable(searchCommand);
}
If you want this to work, you'd have to build the SQL statment dynamically and execute with sp_executesql inside the proc as so:
DECLARE #IntVariable int;
DECLARE #SQLString nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
/* Build the SQL string one time.*/
SET #SQLString =
N'SELECT BusinessEntityID, NationalIDNumber, JobTitle, LoginID
FROM AdventureWorks2012.HumanResources.Employee
WHERE BusinessEntityID = #BusinessEntityID';
SET #ParmDefinition = N'#BusinessEntityID tinyint';
/* Execute the string with the first parameter value. */
SET #IntVariable = 197;
EXECUTE sp_executesql #SQLString, #ParmDefinition,
#BusinessEntityID = #IntVariable;
/* Execute the same string with the second parameter value. */
SET #IntVariable = 109;
EXECUTE sp_executesql #SQLString, #ParmDefinition,
#BusinessEntityID = #IntVariable;
You still have the benefit of using parametrized queries and not exposing yourself to SQL Injection.
Source here.
Another very useful link is this.
Related
This code will perfectly retrieve data if there are no conditional clauses
(a basic select * from table statement), but it fails when I provide username and order by clause
protected void Button2_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["mycon"].ToString());
string cname = TextBox2.Text;
Session[cname] = cname.ToString();
con.Open();
string sql = " select * from customer_reservations where customer_id='"
+ Session[cname] + "' order by reservation_time ";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader reader = cmd.ExecuteReader();
GridView1.DataSource = reader;
GridView1.DataBind();
/*"select *from customer_reservations where customer_id='" + cname +
"' order by reservation_time";
*/
/* select *from customer_reservations */
}
The reservation_time is stored as datetime data type in SQL Server and does seem accessible because when I do a select * statement it does convert 14' O clock to 2pm in browser
Ok, is cname text, or a number? You have to check the database.
However, it always VERY easy to mess up string concatenation, and thus I suggest this:
protected void Button1_Click(object sender, EventArgs e)
{
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["mycon"].ToString()))
{
string cname = TextBox2.Text;
Session["cname"] = cname.ToString();
con.Open();
string sql = " select * from customer_reservations where customer_id = #cname "
+ " order by reservation_time";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.Add("#cname", SqlDbType.NVarChar).Value = cname;
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
}
}
}
So, it tends to be easier to write out the sql without all those quotes and what not. And bonus is we get sql injection safe code.
So try above.
Also, check your on-page load event. If it loads up the grid, or does anything, then you ALWAYS, but ALWAYS want to ONLY have code run on first page load, and hence this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
As a FYI, you would have needed this:
Session["cname"] = cname;
And to get the value out, you need this:
some var = Session["cname"].ToString();
You actually creating a session var of the actual text value!! - not something called "cname".
2nd FYI:
If you want to use paging on the grid, then you can't give the GV a "reader", and thus you need/should use this:
string sql = " select * from customer_reservations where customer_id = #cname "
+ " order by reservation_time";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.Add("#cname", SqlDbType.NVarChar).Value = cname;
DataTable rstData = new DataTable();
rstData.Load(cmd.ExecuteReader());
GridView1.DataSource = rstData;
GridView1.DataBind();
I am working in asp.net. I have a textbox named formidtxt and another textbox is colortxt. Now what I want is that when a user enters an Form ID in formidtxt then at the same time it should start checking whether there already exists a form id with same ID that has been entered and if Form ID already exists in database then the color of colortxt textbox should change to red else it should be green.
I have an idea that it can be done by using events in text boxes but can't understand the working. My database is in SQL Server 2008.
Try this C# code;
private void Page_Load(object sender, EventArgs e)
{
// formidtxt is the name of the textbox
this.formidtxt.TextChanged += FormIDTextBox_TextChanged;
formidtxt.AutoPostBack = true;
}
Note that this method was written inside the Page_Load method.
TextChanged is an event and it occurs when the text is modified in a TextBox.
In this case, when the formidtxt (textbox) text changes, it will call the FormIDTextBox_TextChanged method.
private void FormIDTextBox_TextChanged(object sender, EventArgs e)
{
int x = 0;
// convert textbox text (string) to int
Int32.TryParse(formidtxt.Text, out x);
// call IsIDAvailableDAO method
// x is the converted int value
if (IsIDAvailableDAO(x))
{
colortxt.BackColor = System.Drawing.Color.Red;
}
else
{
colortxt.BackColor = System.Drawing.Color.Green;
}
}
This method will get the text from the textbox (formidtxt) and send it to the IsIDAvailableDAO method as a parameter.
Using the IsIDAvailableDAO method, we can check whether the ID is available in the database or not. If it is available, then the method will return a TRUE boolean value. If not, it will return a False boolean value.
According to that boolean value, you can change the color of the colortxt textbox as you want or do something else.
private Boolean IsIDAvailableDAO(int id)
{
Boolean output;
using (SqlConnection myConnection = new SqlConnection("Data Source=localhost;Initial Catalog=Testing;Integrated Security=True"))
{
string query = #"SELECT CASE WHEN COUNT(ID) >= 1 THEN CAST( 1 as BIT ) ELSE CAST( 0 as BIT )
END As IsAvailable
FROM TableName
WHERE ID = #ID";
SqlCommand cmd = new SqlCommand(query, myConnection);
cmd.Parameters.AddWithValue("#ID", id);
myConnection.Open();
output = (Boolean)cmd.ExecuteScalar();
myConnection.Close();
}
return output;
}
In this method (IsIDAvailableDAO), Please change the query (TableName, ID, etc.) and connectionstring as appropriate.
You also has to add this namespace: using System.Data.SqlClient;
https://www.connectionstrings.com/sql-server-2008/
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/using-namespaces
Im running an update query, it says it is not finding the second parameter (status), although I am clearly sending it. They are in different classes and are being called by a button which sends a mail and then changes the value of a variable (statusRef) in the main table (this field is new).
protected void sendMail(object sender, EventArgs e)
{
BO.Messages mail = new BO.Messages();
string body = "Cuerpo Mensaje";
string title = "Titulo";
string script = "alert(\"An email has been sent to the candidate! \");";
mail.refEmail(emailCandi.Text,title,body);
ScriptManager.RegisterStartupScript(this, GetType(),
"ServerControlScript", script, true);
Email_Sent.Visible = true;
changeRefStatus(Int32.Parse(idCand.Text), "1");
}
protected void changeRefStatus(int id, string status)
{
ASF.HC.JobApplication.BO.User u = new ASF.HC.JobApplication.BO.User();
u.saveStatusRef(id,status);
}
public int saveStatusRef(int id, string status)
{
Entity.User u = new Entity.User();
SqlCommand comando = new SqlCommand("dbo.[user_saveStatusRef]", base.Db);
SqlParameter spSearch = new SqlParameter("#id", System.Data.SqlDbType.Int);
SqlParameter spSearch2 = new SqlParameter("#status", System.Data.SqlDbType.VarChar);
spSearch.Value = id;
spSearch.Value = status;
comando.Parameters.Add(spSearch);
comando.Parameters.Add(spSearch2);
return base.ExecuteScalar(comando);
}
The stored procedure...
ALTER PROCEDURE dbo.user_saveStatusRef
#id int,
#status varchar(5)
AS
UPDATE tbl_user
set statusRef = #status
WHERE id = #id
Maybe a typo but you dont assign Value to spSearch2
spSearch.Value = id;
spSearch.Value = status;
I wrote this code in my login page. My code doesn't any error but update query doesn't apply on my database.
Fist query works and I redirect to index.aspx but update query (second query) doesn't apply!!!!
protected void btnLogin_Click(object sender, EventArgs e)
{
Database db1 = new Database();
string query = "select * from Admins where UserName=#username and cast(Password as varbinary)=cast(#password as varbinary)";
SqlCommand smd = new SqlCommand(query, db1.sc);
smd.Parameters.AddWithValue("#username", txtUsername.Text);
smd.Parameters.AddWithValue("#password", General.CreatePasswordHash(txtPassword.Text));
SqlDataReader sdr = smd.ExecuteReader();
smd.Parameters.Clear();
if (sdr.Read())
{
Session.Add("username", sdr[0].ToString());
string nowEnter = sdr[5].ToString();
query = "update Admins set LastEnter=#lastEnter, NowEnter=#nowEnter where UserName=#username";
string now = General.getPersianDateNow() + " ساعت " + General.getPersianTimeNow();
smd.CommandText = query;
smd.Parameters.AddWithValue("#lastEnter", nowEnter);
smd.Parameters.AddWithValue("#nowEnter", now);
smd.Parameters.AddWithValue("#username", sdr[1].ToString());
sdr.Close();
smd.ExecuteNonQuery();
Response.Redirect("~/admin/Index.aspx", false);
}
else
{
lblError.Visible = true;
}
}
In my opinion the problem is with index of sdr. First one you invoke
Session.Add("username", sdr[0].ToString());
Two lines below you use
smd.Parameters.AddWithValue("#username", sdr[1].ToString());
Anyway the safest way is to create select statement with named colums instead of using *
Check that the value you are using for the username exists in the table.
You're also adding the same parameter twice. I don't know how the SqlCommand class will handle that and I can't test it right now, but I think it might be a good idea to clear your parameters (smd.Parameters.Clear()) between executions.
I have built a custom validator,
I have a sql query like this:
protected void custom_serverValidate(object sender, ServerValidateEventArgs e)
{
connect();
string strSQL = "select EmailAddress from Accounts_Users where EmailAddress=" + REmailTextBox.Text;
SqlCommand cmd = new SqlCommand(strSQL, objConnection);
if (e.Value.ToString() == cmd.ExecuteScalar().ToString())
{
e.IsValid = false;
}
else
e.IsValid = true;
disConnect();
}
when I execute my code in the browser and an email address and submit it , I get the error mentioned in the title. how to fix it ?
You are missing quotes around your email address. However - this is a SQL injection attack waiting to happen. Please switch to using a parameter.
string strSQL = "select EmailAddress from Accounts_Users where EmailAddress = #EmailAddress"
...
cmd.Parameters.AddWithValue("#EmailAddress", REmailTextBox.Text);
You forgot to use the single quotes. Use:
string commandText = "select EmailAddress from Accounts_Users where EmailAddress=#EmailAttress";
SqlCommand cmd = new SqlCommand(commandText, conn);
cmd.Parameters.Add("#EmailAddress", REmailTextBox.Text);