当使用sqldatareader如何在三层架构中解决它时,我得到“读取器关闭时调用Read的无效尝试”

当我点击链接按钮时,它给出的错误是“读取器关闭时无效尝试调用读取”我的DAL方法返回dr是

private SqlDataReader getDownload(string sql) { SqlDataReader dr; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); } return dr; } 

另一种DAL方法是

 public SqlDataReader getDownload(int auto_id) { string sql = "select mfile_name,file_data from Viva_Notice where auto_id=" + auto_id; SqlDataReader dr = getDownload(sql) ; return dr; } 

我的BLL方法是

 public SqlDataReader getDownload(int field) { GetPostAssign mGetPostAssign = new GetPostAssign(); SqlDataReader dr = mGetPostAssign.getDownload(field); return dr; } 

当我打电话给它然后得到“读取器关闭时无效尝试呼叫读取”

 protected void lnkDownload_Click(object sender, EventArgs e) { try { LinkButton lnkbtn = sender as LinkButton; GridViewRow gvrow = lnkbtn.NamingContainer as GridViewRow; if (gvrow.RowIndex < 0) return; int field = Convert.ToInt32(lnkbtn.Attributes["RowIndex"]); SqlDataReader dr = MclsAssignment.getDownload(field); if (dr.Read()) { Response.AddHeader("Content-Disposition", "attachment;filename=\"" + dr["mfile_name"] + "\""); Response.BinaryWrite((byte[])dr["file_data"]); Response.End(); } } catch (Exception) { throw; } } 

这实际上是一个设计问题 – 如果你打算破坏连接,你不能真正返回一个“实时”数据阅读器, SqlDataReader依赖它,即

 SqlDataReader dr; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); } // the SqlConnection is disposed here return dr; // dr is now invalid 

最重要的是,通过返回SqlDataReader ,您将实现细节泄漏到BLL / UI层。 您应该在连接处于活动状态时读取数据并返回实际数据,以保持良好和干净,例如

 public class Download { public string Name { get; set; } public byte[] Data { get; set; } } ... private Download getDownload(string sql) { using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) using (SqlCommand cmd = new SqlCommand("getInfo", con)) { cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; con.Open(); Using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { return new Download { Name = (string)dr["mfile_name"], Data = (byte[])dr["file_data"] }; } } } } 

这是数据访问层的设计问题。 它并没有像应该那样将应用程序与数据库分离。 它只是与数据库不同的接口而不是使用SQL。 你需要完全解耦它们。 那就是你需要将数据对象返回给应用程序。 然后,应使用阅读器在DAL中填充这些数据对象

所以你的方法是这样的:

 private MyFile getDownload(string sql) { SqlDataReader dr; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); return new MyFile { file_name = dr["mfile_name], file_data = dr["file_data] } } } 

using语句在最后一个语句在using块中执行后立即将对象置于上下文中(在本例中为SqlConnection)。 当您在DALfunction之外访问它时,这就是“读取器关闭…”错误的原因。

您应该删除using块并处理更高层或更好的连接打开/关闭,您应该将SqlDataReader转换为DAL方法内的对象或DataTable并返回它。 DataTable示例:

 private DataTable getDownload(string sql) { SqlDataReader dr; DataTable dt; using (SqlConnection con = ConnectionManager.GetDatabaseConnection()) { SqlCommand cmd = new SqlCommand("getInfo", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add("@query", SqlDbType.VarChar).Value = sql; cmd.Connection = con; dr = cmd.ExecuteReader(); dt = new DataTable(); dt.Load(dr); } return dt; } 

你应该改变/添加一个方法

 public DataTable getDownload(string sql) { using (SqlConnection con = new SqlConnection(yourconstring)) { SqlDataAdapter dap = new SqlDataAdapter(sql,con); DataTable dt = new DataTable(); dap.Fill(dt); return dt; } } 

然后在你的下载点击方法

 DataTable dt = MclsAssignment.getDownload(field); if (dt.Rows.Count> 0) { Response.AddHeader("Content-Disposition", "attachment;filename=\"" + (string)dt.Rows[0]["mfile_name"] + "\""); Response.BinaryWrite((byte[])dt.Rows[0]["file_data"]); Response.End(); }