【问题标题】:why get "Cannot read from a closed TextReader"为什么会出现“无法从关闭的 TextReader 中读取”
【发布时间】:2017-05-29 09:14:01
【问题描述】:

我有一个从 Web Api 返回 Json 的 SQL CLR 函数,这是我的代码

[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString Funcion()
{
    SqlString document;
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("URL");
    request.Method = "GET";
    request.ContentLength = 0;
    request.Credentials = CredentialCache.DefaultCredentials;
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Stream receiveStream = response.GetResponseStream();
    StreamReader readStream = new StreamReader(receiveStream);
    document = (SqlString)readStream.ReadToEnd();
    return document;
}

我删除了下一个代码,因为我认为这是问题所在

     //response.Close();
    //readStream.Close();

但我仍然遇到错误

System.ObjectDisposedException: Cannot read from a closed TextReader System.ObjectDisposedException: 
at System.IO.__Error.ReaderClosed()
at System.IO.StreamReader.ReadToEnd()
at UserDefinedFunctions.Funcion()

我使用 ILSpy 检查 dll,我的代码看起来不同 有人可以帮帮我。我在应用程序 cosole 中尝试使用此代码将结果写入文件并完美运行

【问题讨论】:

    标签: .net sql-server sql-server-2012 sqlclr


    【解决方案1】:

    很难确切地说您已将当前代码与注释掉/删除的代码分开。但是一般的概念是用ReadToEnd成字符串返回字符串才是正确的做法。

    如果您不希望这段代码破坏您的 SQL Server,您绝对需要做的一件事是正确处理所有一次性对象。您应该使用 using() 构造,因为它们将包含正确的 try...finally 结构,以确保无论嵌套集中的哪个位置发生异常,所有资源都得到正确处理。

    现在,从 ILspy 获取的图像中显示的代码显示了直接的问题,因为它返回了 readStream.ReadToEnd()。一旦您将代码放入正确的 using 结构中,并在中间执行 document = (SqlString)readStream.ReadToEnd(),那么这将按预期工作。

    string document;
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("URL");
    request.Method = "GET";
    request.ContentLength = 0;
    request.UseDefaultCredentials = true; // don't use CredentialCache.DefaultCredentials;
    
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
      using (Stream receiveStream = response.GetResponseStream())
      {
        using (StreamReader readStream = new StreamReader(receiveStream))
        {
          document = readStream.ReadToEnd();
        }
      }
    }
    
    return new SqlString(document);
    

    更新

    • 使用上面的代码,O.P. 仍然得到Cannot read from a closed TextReader 错误。
    • O.P.提到 Web 服务返回大约 8 MB 的响应。
    • 使用上面的代码,我下载了一个 11.6 MB 的文件,没有问题。
    • 使用上面的代码,O.P. 能够成功地从 https://jsonplaceholder.typicode.com/ 没问题。
    • 问题不是返回数据类型的映射,因为将其映射到NVARCHAR(4000) 而不是NVARCHAR(MAX) 会导致以下错误:

      消息 6522,第 16 级,状态 1,第 2 行
      执行用户定义的例程或聚合“xxxxxx”期间发生 .NET Framework 错误:
      System.Data.SqlServer.TruncationException: 试图将大小为 24233896 字节的返回值或输出参数转换为具有较小大小限制为 8000 字节的 T-SQL 类型。
      System.Data.SqlServer.TruncationException:
      在 System.Data.SqlServer.Internal.CXVariantBase.StringToWSTR(String pstrValue, Int64 cbMaxLength, Int32 iOffset, EPadding ePad)

    【讨论】:

    • 感谢您的帮助!但仍然得到同样的错误:(,
    • 我在控制台应用程序中尝试使用此代码将 json 写入文件并完美运行
    • 这可能与您正在调用的页面有关。我将答案中的代码粘贴到 VS 2015 中的新数据库项目中,将“URL”更改为 SqlString 输入参数,它工作得很好。
    • 是的,它的网络服务有问题,我尝试使用jsonplaceholder.typicode.com 并且效果很好,我会检查网络,因为它有 800 万个字符的结果。感谢您的帮助
    • @VictorHernandez 为什么你没有提到响应应该是 8 MB?这当然是可能影响这一点的相关细节。可能是 SQL Server 的 CLR 主机中的默认超时或最大大小不同(尽管使用 SQL Server 2012 的可能性较小)。控制台应用程序是否与 SQL Server 本身在同一台服务器上运行(不一定是运行 SSMS 的同一台机器)?我将使用 8 MB 文件进行测试并报告。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多