asp.net c# ExecuteReader() error - c#

The following code produces an error.
dbo.getit works fine when I call it directly on the server. The error occurs at cmd.ExecuteReader() . What am I doing wrong?
string user;
string pw;
SqlDataReader dr = null;
SqlConnection conn = new SqlConnection("Data Source=xxx;Initial Catalog=myDB; Integrated Security=True");
user = Username.Text.Trim();
pw = Password.Text.Trim();
conn.Open();
try {
SqlCommand cmd = new SqlCommand("dbo.getit", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#param1", user);
cmd.Parameters.AddWithValue("#param2", pw);
dr = cmd.ExecuteReader();
while ( dr.Read() )
{
Session["username"] = user;
// Session["admin"] =
// Session["completed"] =
Server.Transfer("all_is_well.aspx");
}
conn.Close();
conn.Dispose();
} catch (Exception ex) {
if (dr != null)
{
dr.Close();
conn.Close();
}
Server.Transfer("ERROR.aspx");
}
SOLUTION:
Replace the two corresponding lines above with these:
SqlCommand cmd = new SqlCommand("select * from dbo.getit(#param1, #param2);", conn);
cmd.CommandType = CommandType.text;

This just seems questionable,
Session["username"] = user;
Server.Transfer("all_is_well.aspx");
inside the while loop!
Can you at least finish iterating on the reader, using a temporary object to store the result of the query, and then initialize you session and do the Server.Transfer. .

Server.Transfer terminates execution of the current page and starts execution of a new page for the current request. Also, Transfer calls End, which throws a ThreadAbortException exception upon completion.
I think what you are trying to do (and I am answering based on what you are trying to do - not necessarily best pratice) is verify that the user is authorized/authenticated in some way based on a data store. You'd be better off not using ExecuteReader at all. Use ExecuteScalar. If the result of ExecuteScalar is not null, the user was found.
if (cmd.ExecuteScalar() != null)
{
Server.Transfer("all_is_well.aspx");
}
else
{
Server.Transfer("someErrorPage.aspx");
}

SOLUTION:
Replace the two corresponding lines above with these:
SqlCommand cmd = new SqlCommand("select * from dbo.getit(#param1, #param2);", conn);
cmd.CommandType = CommandType.text;
That worked.

Related

SqlDataReader Can't Proceed into While

I have a problem in SqlDataReader - it cannot proceed into while and cannot while.
Here is my code
List<tmp_WatchList> data = new List<tmp_WatchList>();
using (SqlConnection con = new SqlConnection(conStr))
{
using (SqlCommand cmd = new SqlCommand("sp_CheckPersonList", con))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
SqlDataReader oReader = cmd.ExecuteReader();
while (oReader.Read())
{
//data.Add(new tmp_WatchList
//{
tmp_WatchList l = new tmp_WatchList();
l.id = int.Parse(oReader["id"].ToString());
l.Name = oReader.GetValue(1).ToString();
l.Crime = int.Parse(oReader.GetValue(2).ToString());
data.Add(l);
///});
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
con.Close();
}
}
}
and my stored procedure is:
ALTER PROCEDURE [dbo].[sp_CheckPersonList]
(#Name NVARCHAR(MAX) NULL)
AS
BEGIN
SELECT REPLACE(Name, '.', ''), Crime
FROM [dbo].[tmp_WatchList]
WHERE [Name] LIKE CONCAT('%', REPLACE(#Name, ' ', '%'), '%')
END
Can you tell me how it is done? Or is something wrong with my structure?
You are not opening the connection any where before calling the ExecuteReader, you need to open the database connection, following is the lineo of code to open the connection :
con.Open(); // open connection
SqlDataReader oReader = cmd.ExecuteReader(); // now execute SP
and you do not need finally block for closing the connection, as you are already applyuing the using block on your SqlConnection and SqlCommand which is converted by compiler in to try finally which takes care of disposing the resources and in case of SqlConnection closing the connection.
As other have pointed out, you need to Open the connection, and you can simplify your code removing the try/catch/finally and the explicit con.Close(), which you don't need since you are (corretcly) wrapping the connection within a using
Your code should be something like this (much cleaner than the original one after removing the try/catch/finally):
List<tmp_WatchList> data = new List<tmp_WatchList>();
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("sp_CheckPersonList", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = name;
SqlDataReader oReader = cmd.ExecuteReader();
while (oReader.Read())
{
tmp_WatchList l = new tmp_WatchList();
l.id = int.Parse(oReader["id"].ToString());
l.Name = oReader.GetValue(1).ToString();
l.Crime = int.Parse(oReader.GetValue(2).ToString());
data.Add(l);
}
}
}
If that code raises an exception, it will simply be forwarded to the caller, in a better way comparing to what you did with your throw new Exception(exc.Message), which will loose the original stack trace
Remove the unwanted code..Try Like this..
List<tmp_WatchList> data = new List<tmp_WatchList>();
SqlConnection con = new SqlConnection(conStr);
SqlCommand cmd=new SqlCommand();
cmd.CommmandText="sp_CheckPersonList";
cmd.CommandType = CommandType.Text;
con.Open();
cmd.Connection = con;
cmd.Parameters.AddWithValue("#Name",name);
SqlDataReader oReader = cmd.ExecuteReader();
while (oReader.Read())
{
tmp_WatchList l = new tmp_WatchList();
l.id = int.Parse(oReader["id"].ToString());
l.Name = oReader.GetValue(1).ToString();
l.Crime = int.Parse(oReader.GetValue(2).ToString());
data.Add(l);
}
oReader.Close();
Con.Close();

I'm having an error with Identifying if a record is valid

This code is supposed to identify if the record is not existing it will give you the message "Room is invalid!". But when I tried to run the program it would give me the message several times even though the record is already in the database.
con.Open();
cmd = new SqlCommand(#"Select Room_Name From Rooms", con);
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
roomname = rdr["Room_Name"].ToString();
if (txtRoom.Text != roomname)
{
MessageBox.Show("Room is invalid.");
txtRoom.Focus();
}
}
rdr.Close();
con.Close();
You are reading every record in the database and showing an error on the first invalid match. Filter to your query and use an if instead of a loop
con.Open();
cmd = new SqlCommand(#"Select Room_Name From Rooms where room_name = #roomName", con);
cmd.Parameters.Add("#roomName", SqlDbType.NVarChar, -1).Value = txtRoom.Text;
rdr = cmd.ExecuteReader();
if (rdr.Read())
{
roomname = rdr["Room_Name"].ToString();
}
else
{
MessageBox.Show("Room is invalid.");
txtRoom.Focus();
}
rdr.Close();
con.Close();
Also, as an aside, wrap the DB stuff in using statements so resources are properly disposed of.

There is already an open DataReader associated with this Command which must be closed first error

I have two gridviews in asp.net separated using Ajax's tab container. In one button click event, I want the two gridviews to be populated using a datasource from two different stored procedures.
First gridview - detailed summary of sales per tenant
Second gridview - Consolidated sales group per date
Here's the code
SqlCommand cmd = new SqlCommand("spDSRDetailed", con);
cmd.CommandTimeout = 120;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#dateFrom", txtdatefrom.Text);
cmd.Parameters.AddWithValue("#dateTo", txtdateto.Text);
cmd.Parameters.AddWithValue("#Location", hdnLoc.Value);
cmd.Parameters.AddWithValue("#RP", hdnRP.Value);
try
{
con.Open();
grdDailySalesReport.EmptyDataText = "No Records Found";
grdDailySalesReport.DataSource = cmd.ExecuteReader();
grdDailySalesReport.DataBind();
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
This code works only with one gridview, I know it is possible to do this using SQLDatasource, But that method is not my option because I have used a complex SQL queries and not ideal to do it using SQLDATASOURCE.SELECTCOMMAND.
I tried this and it gives me this error
There is already an open DataReader associated with this Command which must be closed first.
SqlCommand cmd = new SqlCommand("spDSRDetailed", con);
cmd.CommandTimeout = 120;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlCommand cmd2 = new SqlCommand("spDSRConso", con);
cmd2.CommandTimeout = 120;
cmd2.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#dateFrom", txtdatefrom.Text);
cmd.Parameters.AddWithValue("#dateTo", txtdateto.Text);
cmd.Parameters.AddWithValue("#Location", hdnLoc.Value);
cmd.Parameters.AddWithValue("#RP", hdnRP.Value);
cmd2.Parameters.AddWithValue("#dateFrom", txtdatefrom.Text);
cmd2.Parameters.AddWithValue("#dateTo", txtdateto.Text);
cmd2.Parameters.AddWithValue("#Location", hdnLoc.Value);
cmd2.Parameters.AddWithValue("#RP", hdnRP.Value);
try
{
con.Open();
grdDailySalesReport.EmptyDataText = "No Records Found";
grdDailySalesReport.DataSource = cmd.ExecuteReader();
grdDailySalesReport.DataBind();
grdDSRConso.EmptyDataText = "No Records Found";
grdDSRConso.DataSource = cmd2.ExecuteReader();
grdDSRConso.DataBind();
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
You are using SqlCommand.ExecuteReader and the message said :
There is already an open DataReader associated with this Command which
must be closed first
So you need to close the first SqlCommand.ExecuteReader first.
Try this:
SqlDataReader reader = cmd.ExecuteReader();
grdDailySalesReport.EmptyDataText = "No Records Found";
grdDailySalesReport.DataSource = reader;
grdDailySalesReport.DataBind();
reader.Close();
reader = cmd2.ExecuteReader();
grdDSRConso.EmptyDataText = "No Records Found";
grdDSRConso.DataSource = reader;
grdDSRConso.DataBind();
reader.Close();

using the same instance of SQLCommand more than one time in the same code for more than one query?

I have question about using why i can not use the same instance of SQLCommand more than one time in the same code?
I tried the code down here and it runs good for the gridview but when i changed the query by using cmd.CommandText() method it keeps saying:
There is already an open DataReader associated with this Command which must be closed first.
This is the code:
string cs = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
SqlConnection con = new SqlConnection(cs);
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = "Select top 10 FirstName, LastName, Address, City, State from Customers";
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
cmd.CommandText = "SELECT TOP 10 COUNT(CreditLimit) FROM Customers";
int total = (int)cmd.ExecuteScalar();
TotalCreditLble.Text = "The total Credit :" + total.ToString();
}
catch(Exception exp)
{
Response.Write(exp.Message);
}
finally
{
con.Close();
}
The problem is that you are using the SqlCommand object to generate a DataReader via the command.ExecuteReader() command. While that is open, you can't re-use the command.
This should work:
using (var reader = cmd.ExecuteReader())
{
GridView1.DataSource = reader;
GridView1.DataBind();
}
//now the DataReader is closed/disposed and can re-use command
cmd.CommandText = "SELECT TOP 10 COUNT(CreditLimit) FROM Customers";
int total = (int)cmd.ExecuteScalar();
TotalCreditLble.Text = "The total Credit :" + total.ToString();
There is already an open DataReader associated with this Command which must be closed first.
This is the very reason you don't share a command. Somewhere in your code you did this:
cmd.ExecuteReader();
but you didn't leverage the using statement around the command because you wanted to share it. You can't do that. See, ExecuteReader leaves a connection to the server open while you read one row at a time; however that command is locked now because it's stateful at this point. The proper approach, always, is this:
using (SqlConnection c = new SqlConnection(cString))
{
using (SqlCommand cmd = new SqlCommand(sql, c))
{
// inside of here you can use ExecuteReader
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// use the reader
}
}
}
These are unmanaged resources and need to be handled with care. That's why wrapping them with the using is imperative.
Do not share these objects. Build them, open them, use them, and dispose them.
By leveraging the using you will never have to worry about getting these objects closed and disposed.
Your code, written a little differently:
var cs = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
var gridSql = "Select top 10 FirstName, LastName, Address, City, State from Customers";
var cntSql = "SELECT TOP 10 COUNT(CreditLimit) FROM Customers";
using (SqlConnection con = new SqlConnection(cs))
{
con.Open();
try
{
using (SqlCommand cmd = new SqlCommand(gridSql, con))
{
GridView1.DataSource = cmd.ExecuteReader();
GridView1.DataBind();
}
using (SqlCommand cmd = new SqlCommand(cntSql, con))
{
int total = (int)cmd.ExecuteScalar();
TotalCreditLble.Text = "The total Credit :" + total.ToString();
}
}
catch(Exception exp)
{
Response.Write(exp.Message);
}
}
Thank u quys but for the guys who where talking about using block !
why this code work fine which i seen it on example on a video ! It's the same thing using the same instance of SqlCommand and passing diffrent queries by using the method CommanText with the same instance of SqlCommand and it's execute just fine , this is the code :
using (SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandText = "Delete from tbleProduct where ProductID= 4";
int TotalRowsAffected = cmd.ExecuteNonQuery();
Response.Write("Total rows affected :" + TotalRowsAffected );
cmd.CommandText = "Insert into tbleProduct values (4, 'Calculator', 100, 230)";
TotalRowsAffected = cmd.ExecuteNonQuery();
Response.Write("Total rows affected :" + TotalRowsAffected );
cmd.CommandText = "ypdate tbleProduct set QtyAvailbe = 234 where ProductID = 2";
TotalRowsAffected = cmd.ExecuteNonQuery();
Response.Write("Total rows affected :" + TotalRowsAffected );
}

How to retrieve the values in asp.net form from SQL Server 2005

I want the user entered values to get displayed in the form again.. my values get entered into the SQL Server database, but I don't know how to retrieve the values again in the form.. my code is:
SqlDataReader rdr = null;
SqlConnection conn = new SqlConnection("Data Source=Si-6\\SQLSERVER2005;Initial Catalog=emp;Integrated Security=SSPI");
try
{
conn.Open();
SqlCommand cmd=new SqlCommand ("insert into timeday(project,iteration,activity,description,status,hour)values('"+this .name1 .SelectedValue +"','"+this .iteration .SelectedValue +"','"+this .activity .SelectedValue +"','"+this.name2.Text+"','"+this.status .SelectedValue +"','"+this .Text1 .Text +"')",conn );
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr[0]);
}
}
finally
{
if (rdr != null)
rdr.Close();
if (conn != null)
conn.Close();
}
You should:
avoid SQL injection and don't just concatenate together your SQL statements! Use parametrized queries instead!
put your SqlConnection and SqlCommand objects into using blocks
when you want to call an INSERT statement, definitely do not call .ExecuteReader() on your SqlCommand - use .ExecuteNonQuery() instead...
Try something like this:
string connStr = "Data Source=Silverage-6\\SQLSERVER2005;Initial Catalog=emp;Integrated Security=SSPI";
string queryStmt =
"INSERT INTO dbo.timeday(project, iteration, activity, description, status, hour) " +
"VALUES(#Project, #Iteration, #Activity, #Description, #Status, #Hour)";
using(SqlConnection conn = new SqlConnection())
using(SqlCommand _cmd = new SqlCommand(queryStmt, conn))
{
_cmd.Parameters.Add("#Project", SqlDbType.VarChar, 100);
_cmd.Parameters["#Project"].Value = this.name1.SelectedValue.Trim();
// add other parameters the same way....
conn.Open();
int result = _cmd.ExecuteNonQuery();
conn.Close();
}
It would be even better if you:
would retrieve the connection string from a config file once, centrally, and just pass it into this method
would retrieve the values to set from your web UI in your UI code, and then call this business method on a business logic object and pass in the values you've determined
Right now, you're wildly mixing UI code (retrieving the values from the dropdowns and textboxes) with database/business logic code - this is not a very solid design.....
Update: if you want to retrieve values and display them, you can use something like this:
public DataTable GetDataForProject(string projectName)
{
string connStr = "Data Source=Silverage-6\\SQLSERVER2005;Initial Catalog=emp;Integrated Security=SSPI";
string queryStmt =
"SELECT project, iteration, activity, description, status, hour " +
"FROM dbo.timeday " +
"WHERE project = #project";
DataTable resultTable = new DataTable();
using(SqlConnection conn = new SqlConnection())
using(SqlCommand _cmd = new SqlCommand(queryStmt, conn))
{
_cmd.Parameters.Add("#Project", SqlDbType.VarChar, 100);
_cmd.Parameters["#Project"].Value = projectName;
SqlDataAdapter dap = new SqlDataAdapter(_cmd);
dap.Fill(resultTable);
}
return resultTable;
}
Of course:
you might want to select based on other criteria (that would show up in your WHERE clause)
maybe you want to use a SqlDataReader and read that data into domain objects (instead of a DataTable)
but the basic setup - have a specific method, pass in criteria, read the data with SqlConnection and SqlCommand in using blocks - will remain the same.
Once you have the DataTable, you can bind it to an ASP.NET gridview:
DataTable projectData = GetDataForProject("MyProject");
gridView1.DataSource = projectData;
gridView1.DataBind();
After inserting you need to write a query to retrieve records.
Write this
SqlDataReader rdr = null;
SqlConnection conn = new SqlConnection("Data Source=Silverage-6\\SQLSERVER2005;Initial Catalog=emp;Integrated Security=SSPI");
try
{
conn.Open();
SqlCommand cmd=new SqlCommand ();
cmd.CommandText="insert into timeday(project,iteration,activity,description,status,hour)values('"+this .name1 .SelectedValue +"','"+this .iteration .SelectedValue +"','"+this .activity .SelectedValue +"','"+this.name2.Text+"','"+this.status .SelectedValue +"','"+this .Text1 .Text +"')";
cmd.Connection=conn;
int i=cmd.ExecuteNonQuery();
if(i>0)
{
cmd.CommandText="Select * from timeday";
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Console.WriteLine(rdr[0]);
}
}
}
finally
{
if (rdr != null)
rdr.Close();
if (conn != null)
conn.Close();
}

Categories

Resources