CLR 函数不会 return 超过 4000 个字符

CLR function will not return more than 4000 chars

第一次发帖,请多多包涵! :-) VB/C# 的新手,尝试修复调用 Web 服务的 CLR 函数。我拼凑了以下内容:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Collections;
using System.Globalization;

// For the SQL Server integration
using Microsoft.SqlServer.Server;

// Other things we need for WebRequest
using System.Net;
using System.Text;
using System.IO;

public partial class UserDefinedFunctions
{

// Function to return a web URL as a string value.
[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)]

public static SqlChars GET(SqlString uri, SqlString username, SqlString passwd)
{
    // The SqlPipe is how we send data back to the caller
    SqlPipe pipe = SqlContext.Pipe;
    SqlChars document;

    // Set up the request, including authentication
    WebRequest req = WebRequest.Create(Convert.ToString(uri));
    if (Convert.ToString(username) != null & Convert.ToString(username) != "")
    {
        req.Credentials = new NetworkCredential(
            Convert.ToString(username),
            Convert.ToString(passwd));
    }
    ((HttpWebRequest)req).UserAgent = "CLR web client on SQL Server";

    // Fire off the request and retrieve the response.
    // We'll put the response in the string variable "document".
    WebResponse resp = req.GetResponse();
    Stream dataStream = resp.GetResponseStream();
    StreamReader rdr = new StreamReader(dataStream);
    document = new SqlChars(rdr.ReadToEnd());
    if (document.IsNull)
    {
        return SqlChars.Null;
    }

    // Close up everything...
    rdr.Close();
    dataStream.Close();
    resp.Close();

    // .. and return the output to the caller.
    return (document);
}

这将只有 return 4000 个字符,即使它被编码为 sql 个字符。 API 调用可能会 return 在整个库存提取期间超过 14MB。如果我理解正确 sqlChars 转到 varchar(max)(或 nvarchar(max))... 我在这里错过了什么?在 sql 服务器 2005 上为 .Net 3.0 编译,如果有帮助... 安迪

SqlCharsSqlString 都不一定绑定到 NVARCHAR(MAX)NVARCHAR(4000)。在 .NET 中,stringNVARCHAR(MAX),因此 SqlCharsSqlString 都可以映射到 NVARCHAR(MAX)NVARCHAR(4000)。唯一决定它是 MAX 还是 4000(或技术上 14000)的是为输入参数声明的数据类型,return 类型,或 CREATE [PROCEDURE | FUNCTION | AGGREGATE] 语句中的结果集列。所以,你首先需要检查那里。明确定义为NVARCHAR(4000)。如果您只是将它(即 ALTER FUNCTION)更改为 NVARCHAR(MAX),它将 return 一切。

一些其他注意事项:

  1. SQLCLR API 只允许 NVARCHAR,而不是 VARCHAR
  2. 如果您正在使用 Visual Studio / SSDT,您可以修饰您的方法,为 SSDT DDL 生成过程提供提示,告诉它使用 NVARCHAR(MAX)。您可以通过在 [SqlFunction()] 装饰器上方添加以下内容来做到这一点:

    [return: SqlFacet(MaxSize = -1)]
    

    如果您希望 return 类型为 NVARCHAR(250),您可以使用 MaxSize = 250.

  3. 在 SQLCLR 中以这种方式使用外部资源时,您需要非常小心。 AppDomain 可以长时间保持加载状态,并由所有 Session 共享。因此,如果您遇到异常并且没有 using() 构造并且没有 try ... finally 在其中您在打开的资源上调用 Dispose(),那么您可以长时间孤立这些句柄时间。这可能会导致文件锁定(如果它是文件系统操作)或可能会用完网络套接字。您需要非常彻底处理此处的错误处理和资源清理!非常!我在这里有一些其他的答案和附加注释,例如:SQL CLR Web Service Call: Limiting Overhead.

    这意味着,在当前形式下,问题中显示的代码 非常 有风险,因为既不使用 using() 构造也不使用 try...catch...finally. 事实上,在 3 个 .Close() 语句之前 returning return SqlChars.Null; ,你已经做了一件非常糟糕的事情。如果 document.IsNull 曾 returns true,那么此代码将孤立该网络连接和那些外部资源!!!!

  4. 如果这个 UDF 一次只被一个 session / 进程调用,并且永远不会被多个进程调用,那么你没问题。否则,您将 运行 进入默认外部连接数为 2 的问题,该问题会导致其他连接等待直到两个允许的连接之一关闭。在这种情况下,您需要在 ServicePointManager class.
  5. 中设置默认连接数
  6. 没有理由像您那样调用 Convert.ToString({input_parameter})。所有 Sql* 类型都有一个 Value 属性,它 return 是预期 .NET 类型中传入的值。因此,您可以简单地使用 uri.Valueusername.Value
  7. 没有理由指定此方法属性 属性:

    DataAccess = DataAccessKind.Read
    

    如果您要连接到数据库并访问数据,则只需指定 Read。此代码中没有 SqlConnection,因此您不需要此 属性,这会影响性能。同样,您也不需要 using System.Data.SqlClient;.

  8. 有关使用 SQLCLR 的更多信息,请参阅我在 SQLCLR Info
  9. 上发布的资源列表
  10. 对于任何对 WebRequest SQLCLR UDF 的全功能 pre-done 实现感兴趣的人,这样的函数已经存在于 SQL# 库(我编写的)中。该函数名为 INET_GetWebPages 并支持传入所有(或至少大部分)HTTP headers 包括自定义 headers,发送 POST数据,以 VARBINARY 形式返回二进制数据,覆盖默认的每个 URI 最多 2 个连接等。请注意,虽然大多数功能在免费版中可用,但此特定功能仅在完整版(即付费版)中可用版本。