CLR功能不会返回超过4000个字符

时间:2018-05-03 22:59:32

标签: c# sql-server web-services sqlclr

第一次发帖,请善待! :-) 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);
}

即使为sqlChars编码,也只会返回4000个字符。在完全库存拉动期间,API调用可能会返回超过14MB的空间。如果我理解正确sqlChars转到varchar(max)(或nvarchar(max))... 我在这里错过了什么?在sql server 2005上为.Net 3.0编译,如果这有帮助... 安迪

1 个答案:

答案 0 :(得分:3)

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

其他一些说明:

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

    [return: SqlFacet(MaxSize = -1)]
    

    如果您希望返回类型为NVARCHAR(250),则可以使用MaxSize = 250

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

    这意味着,由于未使用using()构造或try...catch...finally,在当前形式中,问题中显示的代码非常存在风险。 并且事实上,在 3 return SqlChars.Null;语句之前返回.Close() ,你已经做了一件非常糟糕的事情。如果document.IsNull曾返回true,则此代码将孤立该网络连接和那些外部资源!!!!!

  4. 如果这个UDF一次只能由一个会话/进程调用,而且从不多次,那么你没问题。否则,您将遇到默认的外部连接数2问题导致其他连接等待,直到两个允许的连接中的一个关闭。在这种情况下,您需要在ServicePointManager类中设置默认连接数。
  5. 没有理由像你一样打电话给Convert.ToString({input_parameter})。所有Sql*类型都具有Value属性,该属性返回预期.NET类型中的传入值。因此,您只需使用uri.Valueusername.Value
  6. 没有理由指定此方法属性:

    DataAccess = DataAccessKind.Read
    

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

  7. 有关使用SQLCLR的更多信息,请参阅我在https://SQLCLR.org/
  8. 上发布的资源列表
  9. 对于对WebRequest SQLCLR UDF的全功能预先实现感兴趣的任何人,SQL#库(我写的)中已经存在这样的函数。该函数名为 INET_GetWebPages ,并支持传入所有(或至少大多数)HTTP标头,包括自定义标头,发送POST数据,将二进制数据恢复为VARBINARY,覆盖每个默认的2个连接URI最大值等。请注意,虽然大多数功能都在免费版本中提供,但此特定功能仅在完整版(即付费版)中可用。