I am trying to update my database with the window form I have created, however an error occurred when I execute the code:
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Data.dll" at comm.ExecuteNonQuery();
Here is the code that I used to connect to my database. Was the code I used to update the database wrong?
string conn=ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
SqlConnection connection = new SqlConnection(conn);
SqlCommand comm = new SqlCommand("UPDATE ExerciseInstruction SET Accumulated_Daily_Sets_Completed = '0' WHERE ExerciseInstructionsID ='" + exerciseInstructionID +"'", connection);
comm.ExecuteNonQuery();
Here is the complete error message :
ExecuteNonQuery requires an open and available Connection. The
connection's current state is closed.
The error message explain all. The command cannot be executed if the code doesn't know how to reach the database. Just a call to connection.Open should fix the problem, however I think you need to use a proper way to execute the query.
This is called Parameterized query. In this way you don't concatenate strings together to form you query text but use parameters to pass values to the database engine and a special formatted string containing the parameters placeholders.
There are two main advantages to do so. It is not possible to target your code with Sql Injection hacks and you don't have to handle quoting around your strings (an infinite source of bugs)
string conn=ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
string cmdText = #"UPDATE ExerciseInstruction
SET Accumulated_Daily_Sets_Completed = 0
WHERE ExerciseInstructionsID =#exid";
using(SqlConnection connection = new SqlConnection(conn))
using(SqlCommand comm = new SqlCommand(cmdText, connection))
{
connection.Open(); // Need this before executing the query
comm.Parameters.Add("#exid", SqlDbType.Int).Value = exerciseInstructionID;
comm.ExecuteNonQuery();
}
Related
I set up a using block for a TransactionScope at the beginning of an ASP.NET action. Somewhere w/i the block I execute a function that both creates a using block for a SqlCommand and w/i that a using block for my SqlConnection.
The blocks for the command and connection open and close as the function is re-used but all w/i the TransactionScope using block. Eventually I call scope.Complete() and when leaving the TransactionScope using block I get an exception saying that no transaction was started that can be committed. In debugging I find that in fact all database calls are just happening w/o a transaction.
Based off the documentation its seeming like the generation of the TransactionScope should be the generation of the transaction, OR, at least that the first time I open any database connection that a transaction should begin because it's w/i the transaction scope block. However this is not the case and I'm unsure why this is.
I actually had this working fine at one point and then all of a sudden, it was not working. So there's something that I did that caused it but I have no idea what it was as the section this was implemented in was completed long ago.
Here's some code:
Starting the transactionScope
using (TransactionScope transactionScope = new TransactionScope())
{
try
{
LegacyDataManager.Start();
//*******************Replace W/ Controller Logic*********************
ViewBag.Message = "Finish";
...
...
...
LegacyDataManager.Commit();
transactionScope.Complete();
}
finally
{
LegacyDataManager.Stop();
}
}
Call to code that executes database update
var theApproval = LegacyDataManager.PrepareForUpdate(Constants.ObjectApproval, row["objectInstance"].ToString(), row["sourceServer"].ToString());
theApproval.write("approvalaction", Request.Form[val].ToString().Substring(0, 1));
theApproval.write("approvaldate", Data_Legacy.getAodDateTimeNow());
theApproval.saveObject();
The database query execution
Data.executeSP("sp_Object_InsertData", SearchNew.generateSQLParameterString("ObjectType", "ObjectInstance", "Parameter", "ParameterValue", "SourceServer"),
SearchNew.generateSQLParameterString(
ObjectType,
ObjectInstance.ToString(),
theNametext,
Regex.Replace(thetheVal, #"\'", "\'\'").Trim(),
SourceServer));
public static DataTable executeSP(string storedProc, SqlParameter[] parms = null, bool gatherParams = true, int commandTimeout = 0)
{
using (SqlCommand cmd = new SqlCommand())
{
if (commandTimeout != 0)
{
cmd.CommandTimeout = commandTimeout;
}
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProc;
handleParameters(cmd.Parameters, storedProc, parms, gatherParams);
using (SqlConnection conn = Data.getConnection("AOD"))
{
if (conn.State != ConnectionState.Open)
conn.Open();
cmd.Connection = conn;
var da = new SqlDataAdapter();
var dt = new DataTable();
da.SelectCommand = cmd;
da.Fill(dt);
return dt;
}
}
}
Thanks for any suggestions in advance.
The good news is that this can just be removed but the bad news is that it creates an annoying programming environment where the XML data files this system is based don't get updated during an error but the updated SQL data that is mirrored out to is retained... Don't ask why that's how it is... it just is.
Apparently I had added a try/catch block around a function that ran a Stored procedure because the data being passed in would sometimes need the function and sometimes not (and thus fail, hence the try catch). Unfortunately when the db call failed the transaction associated w/ the TransactionScope was dropped and the try catch kept the program going.
I removed the the try catch block and replaced it w/ a check on the data passed into the function before determining whether or not to execute the Stored Procedure and now it is once again operating properly.
TL;DR - Check to see if any database calls are failing w/i the transactionScope as it might lead to dropping of the transaction.
Hi have this simple ASPX site setup. In the code behind, I'm connecting to an Oracle database, throwing a SELECT query and putting the result to a DataSet that I can then use/display on the website.
The problem: The query should give me result (works fine inside SQLDeveloper), but when I'm filling the DataSet, it gives me 0 rows every time. No Oracle errors show up, connection to the database opens up fine and the query looks correct.
I would have liked to get some kind of an Oracle error, that would have been easier to troubleshoot. I have tried to find a solution online, but haven't found anything that has helped with my problem.
Here is the relevant code I'm using:
using System.Data.OracleClient;
private OracleConnection conn = new OracleConnection();
-- // Below everyting is in the same method
var ds = new DataSet();
-- // conn.ConnectionString is corretly set
conn.Open(); // connection to database is opened
OracleCommand command = conn.CreateCommand();
var sql = "SELECT * FROM someTable"; -- // the SQL query
command.CommandText = sql;
OracleDataReader reader = command.ExecuteReader();
OracleDataAdapter adapter = new OracleDataAdapter(command);
ds.Tables.Clear();
adapter.Fill(ds);
Here the DataSet (ds) should be full, but it's always empty. Any pointers would be most welcome. Please let me know if I'm missing some information.
I have trouble converting this to stored procedure
//The string included in the sql statement:
string employer = Session["Employer"].ToString();
then the sql statement
update tblWorkData set EmployerName='"+txtemployername.text+"' where EmployerName='"+Employer+"' //the string above
This works fine in asp.net
But when I turn it into stored procedure,
create proc updateWork
#EmployerName nvarchar(max)
as
begin
update tblWorkData set EmployerName=#EmployerName where EmployerName=#EmployerName
end
Now when I execute the sp on asp.net,
string update = "updateWork '"+employer+"','"+txtemployername.text+"'";
I got an error saying "too many arguements". What should I do?
Your stored procedure only takes one argument and you're calling it with two. To fix this you need to alter the procedure to take two arguments like this:
create proc updateWork
#EmployerName nvarchar(max),
#Employer nvarchar(max)
as
begin
update tblWorkData set EmployerName=#EmployerName where EmployerName=#Employer
end
I changed the whereclause as I guess you meant it to be. As it was before it didn't actually do anything at all.
On a side note you might want to look into how to properly call procedures and how to add parameters in a way that isn't vulnerable to SQL injection.
You have to connect to the database in order to execute sql statements:
string employer = Session["Employer"].ToString();
// assume connectionString is a valid connection string
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = "updatework";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#EmployerName", employer);
command.ExecuteNonQuery();
}
I've created a query to select the body of a message from the message database. I'm not sure how to execute it to get the body string back and store it. I've tried using ExecuteReader, ExecuteScalar, and ExecuteNonQuery. None of them work. ExecuteScalar was the closest to working but it only returned the body of the message of the first row no matter which row you were trying to view. Anyone know how to do this? It's gotta be a easy fix.
SqlCommand com = new SqlCommand("SELECT Body FROM Messages WHERE MessageID= MessageID", conn);
com.Connection = conn;
com.Connection.Open();
String body;
body = com.ExecuteScalar.ToString;
That's what I have now. Thanks in advance!
What is messageId in your query? You should be doing something like this
SqlCommand com = new SqlCommand("SELECT Body FROM Messages WHERE MessageID = #MessageId");
com.Parameters.AddWithValue("#MessageId", 1); //Replace 1 with messageid you want to get
string s = com.ExecuteScalar().ToString()
You can use SQLDataAdapter and Datatable for this :
SqlCommand com = new SqlCommand("SELECT MessageID,Body FROM Messages WHERE MessageID= MessageID", conn);
SqlDataAdapter dadapter=new SqlDataAdapter();
DataTable dt = new DataTable();
com.Connection = conn;
com.Connection.Open();
String body;
dadapter.SelectCommand=com;
dadapter.Fill(dt);
body = dr.Rows["Body"].toString();
you should try something like this.
SqlCommand com = new SqlCommand("SELECT Body FROM Messages WHERE MessageID= MessageID", conn);
com.Connection = conn;
com.Connection.Open();
String body;
SqlDataReader dr = com.ExecuteReader();
if(dr.HasRows){
while(dr.Read()){
body+=dr["Body"].ToString();
}
}
I hope this works for you.
Based on your reply to Nudier below, you're trying to pass in the messageID of the selected message by using WHERE MessageID = MessageID
The reason this won't work, and the reason you're always getting the first row returned is that SQL doesn't know that MessageID is a variable you're trying to pass in. As far as SQL knows, MessageID is a column name, so all you're asking SQL to do is select the column "Body" of the row where the column MessageID = the column MessageID, so where MessageID equals itself, which always equates to true. And since ExecuteScalar always returns the first cell of the first row, your query will always return all rows from the Messages table, and the executeScalar will grab the first cell.
Hopefully that made sense, if not, just copy your query and run it against your SQL database, you should see what I mean about it returning all rows as the where clause always equals true.
To fix it, you need to take into account what Anuraj said about adding a parameter.
To pass in a variable to a SQL string in code, you need to parameterise it, then add the relevant parameter, so your SQL should become:
SELECT Body FROM Messages WHERE MessageID=#MessageID
(Notice the addition of the # symbol before the parameter name?)
And directly below that line, you need to add the parameter in code using:
com.AddParameterWithValue("#MessageId", MessageId);
(I think that's right, I copied it from Anuraj, I normally do it slightly differently)
Again, to see this working, you can run it directly against the database with a parameter by using
DECLARE #messsageID AS INTEGER
SET #messageID = 1
SELECT Body FROM Messages WHERE MessageID=#messageID
Have a read of this for more details (or if I haven't managed to be entirely clear) http://www.csharp-station.com/Tutorial/AdoDotNet/lesson06
I have the following code snippet.
SqlCommand cmd = new SqlCommand("SELECT FName,LName FROM EMPLOYEE_TABLE WHERE EmployeeID = '" +TextBox1.Text + "' AND Password = '"+ TextBox2.Text +"'", con);
SqlDataReader x = cmd.ExecuteReader();
try
{
if (x.Read())
{
name = (string)x["FName"] +' '+ (string)x["LName"];
Session["NAME"] = name;
Session["ID"] = TextBox1.Text;
Response.Redirect("sample.aspx?action=On_Click");
}
else
{
errormsg.Text = "login failed.Please enter Valid UserID and Password";
errormsg.ForeColor = System.Drawing.Color.Red;
}
}
catch (Exception exp)
{
errormsg.Text = "Sorry,You dont have access to this portal.";
}
finally
{
x.Close();
con.Close();
}
Now, when i use a valid id (that exists) and password as abc' or 'x'='x then it logs in into the first account of the table in the database. Till this it's fine.
However when I try to debug the code, it throws an error Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack..
Also if it is throwing an error then why is it logging into this 1st account of the database. Note: the first account of the database has a different userid than that which i m providing.
Note: I am the developed of this application. So I'm not doing anything illegal. :)
Look at this part of your SQL:
"' AND Password = '"+ TextBox2.Text +"'"
With your password, it's
"' AND Password = ''x'='x'"
which is not the SQL you want.
Even if you are trying to do SQL injection, you have to result in valid SQL. Usually, it's by ending the statement with a semi-colon after closing the quote. See this:
http://xkcd.com/327/
OK, to provide an answer based on the primary issue you've got (as you've stated, you're new to the SQL Injection issue).
SQL Injection is caused by dynamically building a SQL query using user input as part of the construction. The simplest solution to this in .Net is to create a parameterized query.
I think Jeff Atwood has the most complete yet concise article providing an explanation and complete example here
Quoted from above link:
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
string s = "SELECT email, passwd, login_id, full_name " +
"FROM members WHERE email = #email";
SqlCommand cmd = new SqlCommand(s);
cmd.Parameters.Add("#email", email);
SqlDataReader reader = cmd.ExecuteReader();
The issue at hand:
The reason it's still logging into the account is because the query is still "valid".
The statement will still be executed, and the relevant record will still be returned from the database, no exception will be thrown.
The only way you will stop the login process when invalid data is provided is to validate the input before executing the query. You should always validate user input before sending it off to the database. If the user were to provide:
username'; drop table users;--
as the username, you would be in a LOT of trouble.
The error you're encountering is a debugging error, not an actual program exception. That's why it works when you run it normally.
To remedy the error, I'd first make sure that everything is running with a Debug build. Also, make sure you're currently debugging in the function of the variable you want to inspect. Try stepping (F10) a few times past your breakpoint to refresh the context. There are a slew of other suggestions on the internet for that particular error, so if you're still having problems you might have to do some googling.