ASP.NET SqlDataReader 抛出错误:阅读器关闭时调用 Read 的尝试无效

发布于 2024-08-25 15:51:17 字数 2505 浏览 5 评论 0原文

这个把我难住了。以下是相关代码:

    public AgencyDetails(Guid AgencyId)
    {
        try
        {
            evgStoredProcedure Procedure = new evgStoredProcedure();
            Hashtable commandParameters = new Hashtable();
            commandParameters.Add("@AgencyId", AgencyId);
            SqlDataReader AppReader = Procedure.ExecuteReaderProcedure("evg_getAgencyDetails", commandParameters);
            commandParameters.Clear();

            //The following line is where the error is thrown. Errormessage: Invalid attempt to call Read when reader is closed.
            while (AppReader.Read())
            {
                AgencyName = AppReader.GetOrdinal("AgencyName").ToString();
                AgencyAddress = AppReader.GetOrdinal("AgencyAddress").ToString();
                AgencyCity = AppReader.GetOrdinal("AgencyCity").ToString();
                AgencyState = AppReader.GetOrdinal("AgencyState").ToString();
                AgencyZip = AppReader.GetOrdinal("AgencyZip").ToString();
                AgencyPhone = AppReader.GetOrdinal("AgencyPhone").ToString();
                AgencyFax = AppReader.GetOrdinal("AgencyFax").ToString();
            }
            AppReader.Close();
            AppReader.Dispose();
        }
        catch (Exception ex)
        {
            throw new Exception("AgencyDetails Constructor: " + ex.Message.ToString());
        }
    }

以及 ExecuteReaderProcedure 的实现:

    public SqlDataReader ExecuteReaderProcedure(string ProcedureName, Hashtable Parameters)
    {
        SqlDataReader returnReader;

        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            try
            {
                SqlCommand cmd = new SqlCommand(ProcedureName, conn);
                SqlParameter param = new SqlParameter();
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                foreach (DictionaryEntry keyValue in Parameters)
                {
                    cmd.Parameters.AddWithValue(keyValue.Key.ToString(), keyValue.Value);
                }

                conn.Open();
                returnReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (SqlException e)
            {
                throw new Exception(e.Message.ToString());
            }
        }
        return returnReader;
    }

连接字符串正常工作,而同一类中的其他存储过程运行良好。唯一的问题似乎是从该方法返回 SqlDataReaders 时!他们在标题中抛出错误消息。任何想法都将不胜感激!提前致谢!

This one has me stumped. Here are the relative bits of code:

    public AgencyDetails(Guid AgencyId)
    {
        try
        {
            evgStoredProcedure Procedure = new evgStoredProcedure();
            Hashtable commandParameters = new Hashtable();
            commandParameters.Add("@AgencyId", AgencyId);
            SqlDataReader AppReader = Procedure.ExecuteReaderProcedure("evg_getAgencyDetails", commandParameters);
            commandParameters.Clear();

            //The following line is where the error is thrown. Errormessage: Invalid attempt to call Read when reader is closed.
            while (AppReader.Read())
            {
                AgencyName = AppReader.GetOrdinal("AgencyName").ToString();
                AgencyAddress = AppReader.GetOrdinal("AgencyAddress").ToString();
                AgencyCity = AppReader.GetOrdinal("AgencyCity").ToString();
                AgencyState = AppReader.GetOrdinal("AgencyState").ToString();
                AgencyZip = AppReader.GetOrdinal("AgencyZip").ToString();
                AgencyPhone = AppReader.GetOrdinal("AgencyPhone").ToString();
                AgencyFax = AppReader.GetOrdinal("AgencyFax").ToString();
            }
            AppReader.Close();
            AppReader.Dispose();
        }
        catch (Exception ex)
        {
            throw new Exception("AgencyDetails Constructor: " + ex.Message.ToString());
        }
    }

And the implementation of ExecuteReaderProcedure:

    public SqlDataReader ExecuteReaderProcedure(string ProcedureName, Hashtable Parameters)
    {
        SqlDataReader returnReader;

        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            try
            {
                SqlCommand cmd = new SqlCommand(ProcedureName, conn);
                SqlParameter param = new SqlParameter();
                cmd.CommandType = System.Data.CommandType.StoredProcedure;

                foreach (DictionaryEntry keyValue in Parameters)
                {
                    cmd.Parameters.AddWithValue(keyValue.Key.ToString(), keyValue.Value);
                }

                conn.Open();
                returnReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (SqlException e)
            {
                throw new Exception(e.Message.ToString());
            }
        }
        return returnReader;
    }

The connection string is working as other stored procedures in the same class run fine. The only problem seems to be when returning SqlDataReaders from this method! They throw the error message in the title. Any ideas are greatly appreciated! Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青春如此纠结 2024-09-01 15:51:17

DataReader 通常直接连接到数据库。在这种情况下,当您从该方法返回时,您将从创建 SqlConnetion 对象的 using 语句内部返回。这将调用 SqlConnection 上的 Dispose,并使 SqlDataReader 无用。

试试这个:

public SqlDataReader ExecuteReaderProcedure(string ProcedureName, Hashtable Parameters)
{
    SqlConnection conn = new SqlConnection(connectionString);
    using(SqlCommand cmd = new SqlCommand(ProcedureName, conn))
    {
        cmd.CommandType = System.Data.CommandType.StoredProcedure;

        foreach(DictionaryEntry keyValue in Parameters)
        {
            cmd.Parameters.AddWithValue(keyValue.Key.ToString(), keyValue.Value);
        }

        conn.Open();
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);
    }
}

这样调用:

public AgencyDetails(Guid AgencyId)
{
    evgStoredProcedure Procedure = new evgStoredProcedure();
    Hashtable commandParameters = new Hashtable();
    commandParameters.Add("@AgencyId", AgencyId);
    using(SqlDataReader AppReader = 
        Procedure.ExecuteReaderProcedure("evg_getAgencyDetails", 
                                         commandParameters))
    {
        commandParameters.Clear();

        while(AppReader.Read())
        {
            AgencyName = AppReader.GetOrdinal("AgencyName").ToString();
            AgencyAddress = AppReader.GetOrdinal("AgencyAddress").ToString();
            AgencyCity = AppReader.GetOrdinal("AgencyCity").ToString();
            AgencyState = AppReader.GetOrdinal("AgencyState").ToString();
            AgencyZip = AppReader.GetOrdinal("AgencyZip").ToString();
            AgencyPhone = AppReader.GetOrdinal("AgencyPhone").ToString();
            AgencyFax = AppReader.GetOrdinal("AgencyFax").ToString();
        }
    }
}

AppReaderusing 语句末尾,将调用 AppReader.Dispose。由于您使用 CommandBehavior.CloseConnection 调用了 ExecuteReader,因此处置读取器也将关闭连接。

请注意,我也摆脱了你糟糕的异常处理。切勿使用 ex.Message,除非可能是为了向最终用户显示。其他人都会想要完全例外。此外,如果您允许传播完整的异常,则无需将方法名称作为异常消息的一部分打印。方法名称将出现在堆栈跟踪中。

A DataReader is generally connected directly to the database. In this case, when you return from the method, you're returning from inside the using statement that created the SqlConnetion object. That will call Dispose on the SqlConnection, and render the SqlDataReader useless.

Try this:

public SqlDataReader ExecuteReaderProcedure(string ProcedureName, Hashtable Parameters)
{
    SqlConnection conn = new SqlConnection(connectionString);
    using(SqlCommand cmd = new SqlCommand(ProcedureName, conn))
    {
        cmd.CommandType = System.Data.CommandType.StoredProcedure;

        foreach(DictionaryEntry keyValue in Parameters)
        {
            cmd.Parameters.AddWithValue(keyValue.Key.ToString(), keyValue.Value);
        }

        conn.Open();
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);
    }
}

Call it like this:

public AgencyDetails(Guid AgencyId)
{
    evgStoredProcedure Procedure = new evgStoredProcedure();
    Hashtable commandParameters = new Hashtable();
    commandParameters.Add("@AgencyId", AgencyId);
    using(SqlDataReader AppReader = 
        Procedure.ExecuteReaderProcedure("evg_getAgencyDetails", 
                                         commandParameters))
    {
        commandParameters.Clear();

        while(AppReader.Read())
        {
            AgencyName = AppReader.GetOrdinal("AgencyName").ToString();
            AgencyAddress = AppReader.GetOrdinal("AgencyAddress").ToString();
            AgencyCity = AppReader.GetOrdinal("AgencyCity").ToString();
            AgencyState = AppReader.GetOrdinal("AgencyState").ToString();
            AgencyZip = AppReader.GetOrdinal("AgencyZip").ToString();
            AgencyPhone = AppReader.GetOrdinal("AgencyPhone").ToString();
            AgencyFax = AppReader.GetOrdinal("AgencyFax").ToString();
        }
    }
}

At the end of the using statement for AppReader, AppReader.Dispose will be called. Since you called ExecuteReader with CommandBehavior.CloseConnection, Disposing of the reader will also close the connection.

Note that I got rid of your bad exception handling as well. Never use ex.Message except possibly for displaying to end-users. Everyone else will want the full exception. Also, no need to print the method name as part of the exception message if you're allowing the full exception to propagate. The method name will be in the stack trace.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文