为什么得到 "Cannot read from a closed TextReader"
why get "Cannot read from a closed TextReader"
我有一个 SQL CLR 函数 return 来自 Web Json 的 Api,这是我的代码
[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 中尝试了这段代码,将结果写入文件并完美运行
很难说清楚,因为您已将当前代码与 commented-out/删除的代码分开。但是一般的概念是用ReadToEnd
变成一个字符串到return这个字符串才是正确的做法。
如果您不希望这段代码破坏您的 SQL 服务器,您绝对需要做的一件事就是妥善处理所有一次性物品。您应该使用 using()
构造,因为它们将包含正确的 try...finally
结构,以确保无论在嵌套集合中的哪个位置发生异常,所有资源都得到正确处理。
现在,从 ILspy 获取的图像中显示的代码显示了直接的问题,因为它正在 returning 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 服务 return 的响应大约为 8 MB。
- 使用上面的代码,我顺利下载了一个 11.6 MB 的文件。
- 使用上面的代码,O.P。能够成功地从
https://jsonplaceholder.typicode.com/没问题。
问题是 不是 return 数据类型的映射,因为它映射到 NVARCHAR(4000)
而不是 NVARCHAR(MAX)
将导致以下错误:
Msg 6522, Level 16, State 1, Line 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "xxxxxx":
System.Data.SqlServer.TruncationException: Trying to convert return value or output parameter of size 24233896 bytes to a T-SQL type with a smaller size limit of 8000 bytes.
System.Data.SqlServer.TruncationException:
at System.Data.SqlServer.Internal.CXVariantBase.StringToWSTR(String pstrValue, Int64 cbMaxLength, Int32 iOffset, EPadding ePad)
我有一个 SQL CLR 函数 return 来自 Web Json 的 Api,这是我的代码
[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,我的代码看起来不一样
很难说清楚,因为您已将当前代码与 commented-out/删除的代码分开。但是一般的概念是用ReadToEnd
变成一个字符串到return这个字符串才是正确的做法。
如果您不希望这段代码破坏您的 SQL 服务器,您绝对需要做的一件事就是妥善处理所有一次性物品。您应该使用 using()
构造,因为它们将包含正确的 try...finally
结构,以确保无论在嵌套集合中的哪个位置发生异常,所有资源都得到正确处理。
现在,从 ILspy 获取的图像中显示的代码显示了直接的问题,因为它正在 returning 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 服务 return 的响应大约为 8 MB。
- 使用上面的代码,我顺利下载了一个 11.6 MB 的文件。
- 使用上面的代码,O.P。能够成功地从 https://jsonplaceholder.typicode.com/没问题。
问题是 不是 return 数据类型的映射,因为它映射到
NVARCHAR(4000)
而不是NVARCHAR(MAX)
将导致以下错误:Msg 6522, Level 16, State 1, Line 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "xxxxxx":
System.Data.SqlServer.TruncationException: Trying to convert return value or output parameter of size 24233896 bytes to a T-SQL type with a smaller size limit of 8000 bytes.
System.Data.SqlServer.TruncationException:
at System.Data.SqlServer.Internal.CXVariantBase.StringToWSTR(String pstrValue, Int64 cbMaxLength, Int32 iOffset, EPadding ePad)