【问题标题】:SQL HTTP Function or ProcedureSQL HTTP 函数或过程
【发布时间】:2020-01-23 17:30:38
【问题描述】:

我正在从 sql 中调用我的 web api。 以下代码按预期工作,并将单个大型 JSON 响应返回到表中。

我的问题是把它变成一个有用的函数或过程。

我无法在函数中使用“INSERT EXEC”,我必须这样做,因为响应对于 sp_OAGetProperty 的标量限制来说太大了。

我无法从存储的 proc 版本中获取响应作为选择,因为这会产生嵌套的 EXEC 错误。

我不知道如何把它变成我可以在其他地方调用的东西并实际处理返回的数据

DECLARE @contentType NVARCHAR(64);
DECLARE @postData NVARCHAR(2000);
DECLARE @responseTable table(content nvarchar(max));
DECLARE @ret INT;
DECLARE @token INT;
DECLARE @url NVARCHAR(256);
DECLARE @Authorization NVARCHAR(200);


DECLARE @AccessToken varchar(500) = 'REDACTED'
DECLARE @ApiMethod varchar(200) = 'GET'

SET @contentType = 'application/x-www-form-urlencoded';
SET @postData = 'TestParam=123';
SET @url = 'http://localhost/api/testmethod';

IF @ApiMethod = 'GET'
BEGIN
    SET @url = @url + '?' + @postData;
END

EXEC @ret = sp_OACreate 'MSXML2.ServerXMLHTTP', @token OUT;
EXEC @ret = sp_OAMethod @token, 'open', NULL, @ApiMethod, @url, 'false';
DECLARE @bearer varchar(600) = 'Bearer ' + @AccessToken;
EXEC sp_OAMethod @token, 'SetRequestHeader', NULL, 'Authorization', @bearer
EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Content-type', @contentType;

IF @ApiMethod = 'POST'
BEGIN
    EXEC @ret = sp_OAMethod @token, 'send', NULL, @postData;
END

IF @ApiMethod = 'GET'
BEGIN
    EXEC @ret = sp_OAMethod @token, 'send', NULL, NULL;
END

INSERT INTO @responseTable exec sp_OAGetProperty @token, 'responseText'

EXEC @ret = sp_OADestroy @token;

SELECT * FROM @responseTable

【问题讨论】:

  • 首先想到的是将其转换为 CLR 函数或存储过程,如果您可以使用 CLR。​​
  • 是的,现在正在尝试 CLR,但我对 CLR 的工作原理不是很熟悉,而且这变得很困难
  • 这是关于您必须使用的内容... SQL Server 并不是真正为此类活动而构建的。
  • 知道如何允许 CLR 访问 system.net.http.dll 吗?即使我尝试使用 PERMISSION_SET = UNSAFE 加载,我仍然为程序集“System.Net.Http”创建程序集失败,因为程序集“System.Net.Http”验证失败

标签: sql sql-server asp.net-web-api


【解决方案1】:

如果有人需要这个,我最终使用了一个带有输出参数的存储过程来从 API 返回 json 响应,然后在过程之外对其进行解析。我仍在寻找更好的解决方案,将第 2 部分放入 proc/function 中,但目前可行

CREATE Procedure [dbo].[CallApiProc]
(
    @AccessToken varchar(500),
    @ApiPath varchar(200),
    @ApiMethod varchar(200),
    @FormEncodedBody varchar(max),
    @response varchar(max) OUT
)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @authHeader NVARCHAR(64);
    DECLARE @contentType NVARCHAR(64);
    DECLARE @postData NVARCHAR(2000);
    declare @responseTable table(content nvarchar(max));
    DECLARE @responseText NVARCHAR(max);
    DECLARE @responseXML NVARCHAR(2000);
    DECLARE @ret INT;
    DECLARE @status NVARCHAR(32);
    DECLARE @statusText NVARCHAR(32);
    DECLARE @token INT;
    DECLARE @url NVARCHAR(256);
    DECLARE @Authorization NVARCHAR(200);

    --set your post params
    SET @contentType = 'application/x-www-form-urlencoded';
    SET @postData = @FormEncodedBody;
    SET @url = 'http://localhost/api/' + @ApiPath;

    IF @ApiMethod = 'GET'
    BEGIN
        SET @url = @url + '?' + @FormEncodedBody
    END

    -- Open the connection.
    EXEC @ret = sp_OACreate 'MSXML2.ServerXMLHTTP', @token OUT;
    IF @ret <> 0 
    BEGIN
        declare @errorOpen int = cast('Unable to open API connection' as int);
    END
    -- Send the request.
    EXEC @ret = sp_OAMethod @token, 'open', NULL, @ApiMethod, @url, 'false';
    --set a custom header Authorization is the header key and VALUE is the value in the header
    declare @bearer varchar(600) = 'Bearer ' + @AccessToken;
    EXEC sp_OAMethod @token, 'SetRequestHeader', NULL, 'Authorization', @bearer

    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Content-type', @contentType;

    IF @ApiMethod = 'POST'
    BEGIN
        EXEC @ret = sp_OAMethod @token, 'send', NULL, @postData;
    END

    IF @ApiMethod = 'GET'
    BEGIN
        EXEC @ret = sp_OAMethod @token, 'send', NULL, NULL;
    END

    -- Handle the response.
    EXEC @ret = sp_OAGetProperty @token, 'status', @status OUT;
    EXEC @ret = sp_OAGetProperty @token, 'statusText', @statusText OUT;

    insert into @responseTable exec sp_OAGetProperty @token, 'responseText'


    -- Close the connection.
    EXEC @ret = sp_OADestroy @token;
    IF @ret <> 0 
    BEGIN
        declare @errorClose int = cast('Failed to close API connection' as int);
    END

    select @response = content FROM @responseTable;

END

然后我这样称呼它

declare @AccessToken varchar(500) = 'REDACTED'

declare @StartDate DATETIME = '2019-12-01';
declare @EndDate DATETIME= '2019-12-08';
declare @TimeGrouping INT = 0;
declare @HierarchyGrouping INT = 1;
declare @RecordType INT = 0;
declare @IncludeZeroRecords BIT = 0;
declare @response varchar(max) = '';

declare @results TABLE (
    UserOId BIGINT,
    LocationOId BIGINT,
    ClientUserId varchar(max),
    ClientLocationId varchar(max),
    ClientMarketId varchar(max),
    StraightTime decimal(18,10),
    Overtime decimal(18,10),
    Doubletime decimal(18,10),
    NonCoverageTime decimal(18,10),
    BudgetTime decimal(18,10)
)

declare @formBody varchar(max) = 
'startDate=' + dbo.UrlEncode(convert(varchar, @StartDate, 101)) + 
'&endDate=' + dbo.UrlEncode(convert(varchar, @EndDate, 101)) + 
'&timeGrouping=' + convert(varchar, @TimeGrouping) + 
'&hierarchyGrouping=' + convert(varchar, @HierarchyGrouping) + 
'&recordType=' + convert(varchar, @RecordType) + 
'&includeZeroRecords=' + case when @IncludeZeroRecords = 1 then 'true' ELSE 'false' END;

EXEC dbo.CallApiProc @AccessToken, 'Employment/TimeBreakdown', 'GET', @formBody, @response OUTPUT;

INSERT INTO @results
SELECT 
    JSON_VALUE(value, '$.UserOId'),
    JSON_VALUE(value, '$.LocationOId'),
    JSON_VALUE(value, '$.ClientUserId'),
    JSON_VALUE(value, '$.ClientLocationId'),
    JSON_VALUE(value, '$.ClientMarketId'),
    JSON_VALUE(value, '$.StraightTime'),
    JSON_VALUE(value, '$.Overtime'),
    JSON_VALUE(value, '$.Doubletime'),
    JSON_VALUE(value, '$.NonCoverageTime'),
    JSON_VALUE(value, '$.BudgetTime')
FROM OPENJSON(@response)

SELECT *, u.* FROM @results r
JOIN [User] u on r.UserOId = u.OId

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
相关资源
最近更新 更多