C # SQL Server CLR Ошибка запроса на функции GET и POST - PullRequest
0 голосов
/ 01 ноября 2018

Я следовал документации GitHub для реализации http-запросов с расширением CURL, работы в SQL Server 2008 R2, Visual Studio 2010 и .NET 3.5.

Мне удалось скомпилировать и правильно подписать .dll в Visual Studio, чтобы затем создать схемы и функции в SQL Server, так как все работает правильно, однако я могу выполнить GET и POST из SQL Server, однако, когда я хочу выполнить ПОЛУЧИТЬ или POST в SABA API, он генерирует серию ошибок.

Ошибка .NET Framework при выполнении пользовательского задания подпрограмма или агрегат "XGET": System.Net.WebException: базовый соединение было закрыто: при отправке произошла непредвиденная ошибка. ---> System.IO.IOException: получил неожиданный EOF или 0 байтов от транспортный поток. System.IO.IOException: в System.Net.FixedSizeReader.ReadPacket (буфер Byte [], смещение Int32, Количество Int32) в System.Net.Security.SslState.StartReadFrame (Byte [] буфер, Int32 readBytes, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.StartReceiveBlob (буфер Byte [], AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.CheckCompletionBeforatextReceive (ProtocolTokat сообщение, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.StartSatdBlob (Byte [] входящий, Int32 считать, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ForceAuthattication (логическое значение receiveFirst, Байт [] буфер, AsyncProtocolRequest asyncRequest) в System.Net.Security.SslState.ProcessAuthattication (LazyAsyncResult lazyResult) в System.Net.TlsStream.CallProcessAuthattication (состояние объекта) в System.Threading.ExecutionContext.runTryCode (Object userData) в System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup (TryCode код, CleanupCode backoutCode, Object userData) в System.Threading.ExecutionContext.RunInternal (ExecutionContext executeContext, обратный вызов ContextCallback, состояние объекта) в System.Threading.ExecutionContext.Run (ExecutionContext executeContext, обратный вызов ContextCallback, состояние объекта) в System.Net.TlsStream.ProcessAuthattication (результат LazyAsyncResult)
в System.Net.TlsStream.Write (буфер Byte [], смещение Int32, размер Int32) в System.Net.PooledStream.Write (буфер Byte [], смещение Int32, Int32). размер) в System.Net.ConnectStream.WriteHeaders (Boo ... System.Net.WebException: в System.Net.WebCliatt.DownloadDataInternal (адрес Uri, веб-запрос & запрос) в System.Net.WebCliatt.DownloadString (адрес Uri) ...

Это код сборки

using Microsoft.SqlServer.Server;
using System;
using System.Data.SqlTypes;
using System.Net;
using System.Threading;

public static class Curl
{
    [SqlFunction]
    [return: SqlFacet(MaxSize = -1)]
    public static SqlChars Get(SqlChars H, SqlChars url)
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
        var client = new WebClient();
        AddHeader(H, client);

        return new SqlChars(
                client.DownloadString(
                    Uri.EscapeUriString(url.ToSqlString().Value)
                    ).ToCharArray());
    }

    [SqlProcedure]
    public static void Post(SqlChars H, SqlChars d, SqlChars url)
    {
        var client = new WebClient();
        AddHeader(H, client);
        if (d.IsNull)
            throw new ArgumentException("You must specify data that will be sent to the endpoint", "@d");
        var response =
                client.UploadString(
                    Uri.EscapeUriString(url.ToSqlString().Value),
                    d.ToSqlString().Value
                    );
        SqlContext.Pipe.Send("Request is executed. " + response);
    }

    [SqlProcedure]
    public static void PostWithRetry(SqlChars H, SqlChars d, SqlChars url)
    {
        var client = new WebClient();
        AddHeader(H, client);
        if (d.IsNull)
            throw new ArgumentException("You must specify data that will be sent to the endpoint", "@d");
        int i = RETRY_COUNT;
        string response = "";
        do try
            {
                response =
                        client.UploadString(
                            Uri.EscapeUriString(url.ToSqlString().Value),
                            d.ToSqlString().Value
                            );
                i = -1;
                break;
            }
            catch (Exception ex)
            {
                SqlContext.Pipe.Send("Error:\t" + ex.Message + ". Waiting " + DELAY_ON_ERROR + "ms.");
                i--;
                Thread.Sleep(DELAY_ON_ERROR);
            }
        while (i > 0);
        if (i == -1)
            SqlContext.Pipe.Send("Request is executed." + response);
    }

    static readonly int RETRY_COUNT = 3;
    static readonly int DELAY_ON_ERROR = 50;

    public static bool IsNullOrWhiteSpace(this string theString)
    {
        if (theString == null)
        {
            return false;
        }

        if (theString.Trim() == string.Empty)
        {
            return false;
        }
        return true;
    }

    private static void AddHeader(SqlChars H, WebClient client)
    {
        if (!H.IsNull)
        {
            string header = H.ToString();
            if (!IsNullOrWhiteSpace(header))
                client.Headers.Add(HttpRequestHeader.UserAgent, header);
        }
    }
};

А это как использовать в SQL Query

declare @hkey nvarchar(4000) = 'SabaCertificate: 31336132353061666330315E235E756F6E6555E6261536974655E235E656E5F55535E235E536162615E235E24414021463393C69358BE384802BA1BBEAD3B4661862F193021435F7E28A30F7540FE661B9C5F30FDB06C';
declare @endpoint nvarchar(1000) = 'https://libertad-api.sabacloud.com/v1/location?count=10&startPage=1';
select curl.xget(@hkey, @endpoint)

Я уже тестировал его в PostMan, вводя заголовок SabaCertificate, и, если он выдает мне результат, однако, если сертификат неверен, он также выдает ответ, и он не отображается.

Пример неверного запроса:

{"errorCode":123,"errorMessage":"Invalid or expired Certificate"}

Но это также не дает мне ответа об ошибке сертификата, которую я должен изменить в своем WebClient, чтобы это работало.

Я добавил, что сертификат слишком большой, потому что иногда я получаю эту ошибку:

Идентификатор, который начинается с 'SabaCertificate: 31336132353061666330315E235E756F6E6555E6261536974655E235E656E5F55535E235E536162615E235E24414021463393C69358BE384802BA1BBEAD3B4661862F193021435F7E28A30F7540FE661B9C5F30FDB06C» слишком долго Максимальная длина 128.

1 Ответ

0 голосов
/ 01 ноября 2018

Одна определенная проблема в коде - это небольшое изменение, внесенное вами в исходный код. В вашем AddHeader методе у вас есть следующая строка:

client.Headers.Add(HttpRequestHeader.UserAgent, header);

Вам необходимо удалить HttpRequestHeader.UserAgent, потому что теперь код создает заголовок «UserAgent» со значением того, что вы передаете, например «SabaCertificate: 31336132 ....».

Вам также нужно будет изменить протоколы безопасности, которые вы устанавливаете, поскольку они не верны. Вам следует попробовать:

ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072; // TLS 1.2

Поскольку вы используете .NET 3.5 через SQL Server 2008 R2, вы не можете указать SecurityProtocolType.Tls12, так как это значение еще не было добавлено в перечисление в Framework версии 3.5, поэтому вы должны использовать числовое значение, как показано выше. Имейте в виду, что фактическая способность выполнять протокол безопасности является функцией базовой ОС, поэтому вполне возможно, что более старая версия Windows / Windows Server не поддерживает TLS 1.2 или может потребоваться изменить настройки реестра, чтобы Сделай так. Вам придется поиграть с этим, если вы продолжите получать подобные ошибки от System.Net.TlsStream.

Также следующая ошибка:

Идентификатор, начинающийся с 'SabaCertificate: 31336 ... 30FDB06C', слишком длинный. Максимальная длина 128.

от ошибки пользователя. «Идентификатор» - это имя элемента в SQL Server (объекты, логины, переменные и т. Д.). Это означает, что вы делаете что-то другое (и неправильно), когда возникает эта ошибка, но я не понимаю, как это может происходить из вашего кода, по крайней мере, не из метода Get, поскольку он не имеет внутреннего взаимодействия с базой данных. .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...