Функция CLR не вернет больше 4000 символов - PullRequest
0 голосов
/ 04 мая 2018

первый раз, пожалуйста, будьте добры! :-) Новое в VB / C #, Попытка исправить функцию 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);
}

Это вернет только 4000 символов, даже если оно закодировано для sqlChars. Вызов API может потенциально вернуть более 14 МБ во время полного извлечения ресурсов. Если я правильно понимаю, sqlChars переходит к varchar (max) (или nvarchar (max)) ... Что мне здесь не хватает? скомпилировано для .Net 3.0 на SQL Server 2005, если это помогает ... Andy

1 Ответ

0 голосов
/ 04 мая 2018

Ни SqlChars, ни SqlString не обязательно связаны либо с NVARCHAR(MAX), либо с NVARCHAR(4000). В .NET string равен NVARCHAR(MAX), поэтому SqlChars и SqlString могут отображаться как NVARCHAR(MAX), так и NVARCHAR(4000). Единственное, что определяет, является ли это MAX или 4000 (или технически 1 - 4000), это тип данных, объявленный для входного параметра, типа возвращаемого значения или столбца набора результатов в операторе CREATE [PROCEDURE | FUNCTION | AGGREGATE]. Итак, сначала нужно проверить там. Он четко определен как NVARCHAR(4000). Если вы просто измените его (т.е. ALTER FUNCTION) на NVARCHAR(MAX), он вернет все.

Некоторые другие заметки:

  1. API SQLCLR допускает только NVARCHAR, но не VARCHAR.
  2. Если вы используете Visual Studio / SSDT, вы можете украсить свой метод, чтобы предоставить подсказку для процесса генерации DDL SSDT, которая скажет ему использовать NVARCHAR(MAX). Вы можете сделать это, добавив следующее над декоратором [SqlFunction()]:

    [return: SqlFacet(MaxSize = -1)]
    

    Если бы вы хотели, чтобы возвращаемый тип был NVARCHAR(250), вы бы использовали MaxSize = 250.

  3. Вы должны быть очень осторожными при использовании внешних ресурсов таким способом в SQLCLR. Домен приложений может оставаться загруженным в течение длительного времени и является общим для всех сеансов. Таким образом, если у вас есть исключение, и нет никакой конструкции using() и нет try ... finally, в которой вы вызываете Dispose() для открытого ресурса (-ов), то вы можете оставить эти дескрипторы надолго. Это может привести к блокировке файлов (если это операция с файловой системой) или может использовать сетевые сокеты. Вы должны быть очень внимательными в обработке ошибок и очистке ресурсов здесь! ОЧЕНЬ! У меня есть некоторые другие ответы здесь с дополнительными примечаниями, такими как: Вызов веб-службы SQL CLR: ограничение накладных расходов .

    Это означает, что в его текущей форме код, показанный в вопросе, является очень рискованным из-за того, что не используется ни конструкция using(), ни try...catch...finally. И на самом деле, вы уже делаете ОЧЕНЬ ПЛОХО, возвращая return SqlChars.Null; до 3 .Close() операторов. Если document.IsNull когда-либо вернет true, то этот код потеряет связь с сетевым подключением и этими внешними ресурсами !!!!!

  4. Если этот UDF будет вызываться только одним сеансом / процессом за раз, а не несколькими, то все в порядке. В противном случае вы столкнетесь с проблемой количества внешних подключений по умолчанию, равной 2, которая приводит к тому, что дополнительные подключения ожидают закрытия одного из двух разрешенных подключений. В этом случае вам нужно будет установить количество подключений по умолчанию в классе ServicePointManager.
  5. Нет причин звонить Convert.ToString({input_parameter}), как вы делаете. Все типы Sql* имеют свойство Value, которое возвращает переданное значение в ожидаемом типе .NET. Таким образом, вместо этого вы просто используете uri.Value и username.Value и т. Д.
  6. Нет причин указывать это свойство атрибута метода:

    DataAccess = DataAccessKind.Read
    

    Вы указываете Read, только если вы устанавливаете соединение с БД и получаете доступ к данным. В этом коде нет SqlConnection, поэтому вам не нужно это свойство, которое снижает производительность. В том же духе вам также не нужно using System.Data.SqlClient;.

  7. Для получения дополнительной информации о работе с SQLCLR в целом, пожалуйста, смотрите список ресурсов, которые я разместил на https://SQLCLR.org/
  8. Для тех, кто заинтересован в полностью функциональной, предварительно выполненной реализации UDF SQLCLR WebRequest, такая функция уже существует в библиотеке SQL # (которую я написал). Функция называется INET_GetWebPages и поддерживает передачу всех (или, по крайней мере, большинства) заголовков HTTP, включая настраиваемые заголовки, отправку данных POST, получение двоичных данных в виде VARBINARY, переопределение соединения по умолчанию 2 на максимум URI, и т.д. Обратите внимание, что хотя большинство функций доступно в бесплатной версии, эта конкретная функция доступна только в полной (то есть платной) версии.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...