This is my C# code, and I get this error
An explicit value for the identity column in table 'tblImages' can only be specified when a column list is used and IDENTITY_INSERT is ON.
public partial class _Default : System.Web.UI.Page
{
// string strconn= ConfigurationManager.ConnectionStrings["con"].ConnectionString;
SqlConnection conn=new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=E:\Final_Year_Project\ProjectFiles\ComSysForDeafAndDumb\App_Data\Database.mdf;Integrated Security=True");
static string query="";
static int myID = 989;
static string imgName;
static string imgSize;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
lblMessage.Visible = false;
hyperlink.Visible = false;
}
}
protected void btnUpload_Click(object sender, EventArgs e)
{
string b = "";
FileUpload1.SaveAs(Request.PhysicalApplicationPath +"./images/"+ FileUpload1.FileName.ToString());
b="~/images/"+ FileUpload1.FileName.ToString();
query = "insert into tblImages values ("+myID+",'"+imgName+"','"+imgSize+"','"+b+"','"+txtdes.Value+"')";
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
Response.Write("successful");
imgUpload.ImageUrl = b;
}
}
When you do this:
insert into tblImages values (123, 'some value', 'another value')
The database will map the supplied values directly to the column list in the table. But one of your columns does not allow explicitly inserted values. Specifically the identity column, which is usually the first column in the table and usually called something like ID.
Instead of trying to insert into all columns, explicitly insert into the columns you want. We don't know the structure of your table, but as an example the INSERT command would look something like this:
insert into tblImages (ImageName, ImageSize) values ('some value', 'another value')
Where ImageName and ImageSize would be names of your columns. Expand this to include all of the columns into which you want to insert values, and to include all of the values you're trying to insert for that record. Basically, explicitly specify which columns you want to write to and don't try to write to the identity column.
Also, and this is important, your code is wide open to SQL injection. This question has some good explanations and examples of how to address that. Basically you should always treat user input as values and not as executable code in your SQL commands.
Related
I have a web form with a gridview and two datepickers and a submit to submit the new query with the datetime constraints. to be the start and end dates to filter the data. The data loads fine without the data and when the submit button with the chosen dates is clicked, nothing happens. I wonder if the filtered data isn't being bound properly(I'm new to web forms and gridview.)
Here is the codebehind for the page:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
BindDataToGridView();
}
protected void dashboard_RowEditing(object sender, GridViewEditEventArgs e)
{
gridErrors.Text = string.Empty;
dashboard.EditIndex = e.NewEditIndex;
BindDataToGridView();
}
protected void dashboard_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
dashboard.EditIndex = -1;
BindDataToGridView();
}
protected void dashboard_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
dashboard.PageIndex = e.NewPageIndex;
BindDataToGridView();
}
protected void dashboard_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
gridErrors.Text = string.Empty;
GridViewRow tabRow = (GridViewRow)dashboard.Rows[e.RowIndex];
HiddenField hdnTabId = (HiddenField)tabRow.FindControl("hdnTabId");
TextBox TxtName = (TextBox)tabRow.Cells[1].Controls[0];
}
protected void button1_Click(object sender, EventArgs e)
{
var start = startDate.Text;
var startTime = DateTime.Parse(start);
var sqlStart = startTime.ToString("yyyy-MM-dd");
var end = endDate.Text;
var endTime = DateTime.Parse(end);
var sqlEnd = endTime.ToString("yyyy-MM-dd");
string sqlQuery = "SELECT TOP(100) TabID, TabName, Title, CreatedOnDate, TabPath From TableName " +
"where CreatedOnDate >= " + sqlStart + " and CreatedOnDate <= " + sqlEnd + " Order By TabName";
BindDataToGridView(sqlQuery);
}
public void BindDataToGridView(string sqlQuery =
"SELECT TOP(100) TabID, TabName, Title, CreatedOnDate, TabPath From TableName Order By TabName")
{
var connectionFromConfig = WebConfigurationManager.ConnectionStrings["ConnString"].ConnectionString;
using (SqlConnection db = new SqlConnection(connectionFromConfig))
{
try
{
db.Open();
SqlCommand command = new SqlCommand(sqlQuery, db);
SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
if (dataSet.Tables[0].Rows.Count > 0)
{
dashboard.DataSource = dataSet;
dashboard.DataBind();
}
}
catch (SqlException ex)
{
gridErrors.Text = ex.Message;
}
finally
{
db.Close();
db.Dispose();
}
}
}
OnPageIndexChanging Method
protected void dashboard_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
dashboard.PageIndex = e.NewPageIndex;
BindDataToGridView();
}
ok, you found the issue (missing quotes). But, at the end of the day?
Yes, everyone will come pile in and note how "when" taking user input, you don't want to concatenate into the sql (too high risk for sql injection).
However, JUST telling you not to concatenate parameters don't help UNLESS we ALSO give you a nice design approach. Looking at your code, you did a GREAT idea to have one grid view load routine. And you ALSO want with great ease to pass sql to that one routine. However, that great idea + goal conflicts with using strong typed parameters.
So, lets kill two birds with one stone here.
and find that using parameters is often LESS code over all then a long messy sql string, which is prone to errors (quite much why you had to post here).
And for numbers - no quotes, for strings - yes, and for dates, again yes. So that's an extra developer workload. And that long messy string is HARD to write, debug, and manage.
So, I suggest this code:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
BindDataToGridView();
}
void BindDataToGridView(SqlCommand cmdSQL = null)
{
// default sql
if (cmdSQL is null)
{
cmdSQL = new
SqlCommand("SELECT TabID, TabName, Title, CreatedOnDate, TabPath From TableName Order By TabName");
}
using (cmdSQL)
{
cmdSQL.Connection = new SqlConnection(conString);
cmdSQL.Connection.Open();
DataTable rst = new DataTable();
rst.Load(cmdSQL.ExecuteReader());
dashboard.DataSource = rst;
dashboard.DataBind();
}
}
note several things:
We did NOT have to create a separate connection object - sqlcommand has one!!
(and since we did not create a separate connection object, then disposing of the sql command takes care of that with our using block!!!
We did not need a separate datatable/dataset, and we did NOT need a data adaptor, and we did NOT need a reader either!! (sql command object has a reader too!!!).
So, now we can call our load grid without a parameter.
But, for the case WHEN we want to pass sql with parameters? Then we can do this:
{
string sqlQuery
= "SELECT TabID, TabName, Title, CreatedOnDate, TabPath From TableName " +
"WHERE CreatedOnDate >= #Start AND CreatedOnDate <= #End ORDER By TabName";
SqlCommand cmdSQL = new SqlCommand(sqlQuery);
cmdSQL.Parameters.Add("#Start", SqlDbType.Date).Value = startDate.Text;
cmdSQL.Parameters.Add("#End", SqlDbType.Date).Value = endDate.Text;
BindDataToGridView(cmdSQL);
}
So, in fact, we can have parameters, we can have less code. We can have easy to read SQL, and we can pass the cmd SQL to that one routine.
So it NOT ONLY the suggesting to not concatenate strings, but with the right approach, we don't have to, we get strong data type conversion, and less code, and even less chances of errors in that code.
Also, check if the sql server column is a date, or datetime. If it is datetime, then specify that data type in the query parameter.
Also, you can droop the TOP clause - it only required when creating a SQL view which in theory does not support a sorted output. But for raw sql, then you can drop the TOP clause.
I needed to add single quotes before and after the sqlStart and sqlEnd variables for Sql Server to use the values with comparison operators.
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
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.
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.
My registration form has got a CreateUserWizard. I used its event that is fired after the user is created.
Then I obtain the users identity and key. In the last line, I send the unique key to a function inside a class that should insert the key into the Users table (the field is a primary key and is unique).
public partial class Registration : System.Web.UI.Page
{
protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
MembershipUser CurrentUser = Membership.GetUser(User.Identity.Name);
int i =(int) CurrentUser.ProviderUserKey;
RegisterAdo.InsertUsers(i);
}
}
Below, I execute the query with the value that I passed and insert the user into a database
class RegisterAdo
{
public static void InsertUsers(int UsersIDentity)
{
string myConnectionString = WebConfigurationManager.ConnectionStrings["YourGuruDB"].ConnectionString;
SqlConnection sqlConnect = new SqlConnection(myConnectionString);
SqlCommand sqlCommand = new SqlCommand(RegisterAdo.insertCommand(UsersIDentity), sqlConnect);
try
{
sqlConnect.Open();
sqlCommand.ExecuteNonQuery();
}
catch (Exception x)
{
}
finally
{
sqlConnect.Close();
}
}
public static String insertCommand(int UsersIdentityToinsert)
{
string insertCommand="INSERT INTO Users(";
insertCommand += "UserID)";
insertCommand += "VALUES('";
insertCommand += UsersIdentityToinsert+"')";
return insertCommand;
}
My question is whether it is the best way to insert UserID into a table, and whether I do it right at all. I need the UserID to be unique, and the whole command executed with no fail...(just after the user was created and the whole UserCreateUser finished validating the user!!!
I would change two things mainly:
don't concatenate together your SQL statement - this opens doors to SQL injection attacks. Use parametrized queries instead - they are both safer, and they perform better (since only a single copy of the query's execution plan needs to be created and cached and will be reused over and over again)
put your SqlConnection and SqlCommand objects into using blocks so that they'll be automatically freed / disposed when the using blocks ends (and you can save yourself the finally block of the try...catch construct, too!).
So my code would look like this
public static void InsertUsers(int UsersIDentity)
{
string myConnectionString = WebConfigurationManager.ConnectionStrings["YourGuruDB"].ConnectionString;
string insertStmt =
"INSERT INTO dbo.Users(UserID) VALUES(#UserID)";
using(SqlConnection _con = new SqlConnection(myConnectionString))
using(SqlCommand _cmd = new SqlCommand(insertStmt, sqlConnect))
{
_cmd.Parameters.Add("#UserID", SqlDbType.Int).Value = UsersIDentity;
try
{
_con.Open();
_cmd.ExecuteNonQuery();
_con.Close();
}
catch (Exception x)
{
// do something if error occurs
}
}