web-dev-qa-db-fra.com

Appel d'un SOAP webservice à partir d'une procédure stockée SQL

J'essaye de construire une procédure stockée dans TSQL pour appeler un webservice. Je l'ai déjà fait dans Oracle, mais il semble que ce ne soit pas si facile dans MSSQL. Il y a bien sûr de nombreuses raisons de ne pas le faire dans un proc stocké, mais comme cette procédure ne doit être utilisée que dans un lot quotidien, les performances ne sont pas trop problématiques. La chose que je veux faire est la suivante: Envoyez un nom complet au webservice, le webservice renverra un nom divisé en choses comme prénom, préfixe, nom de famille, etc. Les valeurs retournées devront être écrites dans une table.

J'ai trouvé une procédure intéressante sur http://www.vishalseth.com/post/2009/12/22/Call-a-webservice-from-TSQL- (Stored-Procedure) -using-MSXML.aspx qui semblait faire exactement ce que je voulais, mais dès que vous ajoutez un corps à l'appel, je rencontre des erreurs comme "Le paramètre est incorrect". Cela est également indiqué dans l'article, et il n'y a apparemment pas de solution facile. J'ai certainement besoin d'envoyer un corps de demande.

J'ai également lu de nombreux articles sur la résolution de ce problème avec CLI ou le "Web Service Task Editor", ou "SSIS", je n'ai trouvé aucun didacticiel sur le point de départ. Pour l'instant, je n'ai que Microsoft SQL Server Management Studio.

Je suis d'ailleurs sur SQL Server 2012.

Avez-vous des idées sur la direction à prendre avec cela?

J'ai déjà trouvé cette description, qui semble assez propre: http://www.databasejournal.com/features/mssql/article.php/3821271/Calling-a-Web-Service-from-within-SQL -Server.htm Cependant, après avoir installé Visual Studio 2012 et créé un "projet de base de données SQL Server", je ne peux pas choisir "Ajouter une référence Web" dans le menu contextuel de la solution, il y a juste une telle option dans le menu.

7
ErikL

Dans le passé, j'ai utilisé la méthode suivante, ce n'est peut-être pas la meilleure méthode de nos jours, mais cela a fonctionné avec succès pour moi:

DECLARE @obj int,
        @url VarChar(MAX),
        @response VarChar(MAX),
        @requestHeader VarChar(MAX),
        @requestBody VarChar(MAX)

SET @url = 'http://....'

SET @requestBody = '<soapenv:Envelope>
                     <soapenv:Header/>
                      <soapenv:Body>
                       ...
                      </soapenv:Body>
                     </soapenv:Envelope>'

EXEC sp_OACreate 'MSXML2.ServerXMLHttp', @obj OUT
EXEC sp_OAMethod @obj, 'Open', NULL, 'GET', @url, false
EXEC sp_OAMethod @obj, 'setRequestHeader', NULL, 'Content-Type', 'text/xml;charset=UTF-8'
EXEC sp_OAMethod @obj, 'setRequestHeader', NULL, 'SOAPAction', 'POST'
EXEC sp_OAMethod @obj, 'setRequestHeader', NULL, 'Content-Length', LEN(@requestBody)
EXEC sp_OAMethod @obj, 'send', NULL, @requestBody
EXEC sp_OAGetProperty @obj, 'responseText', @response OUT


SELECT @response [RESPONSE]

EXEC sp_OADestroy @obj

Je l'ai utilisé pour appeler un webservice qui produit un rapport et l'envoie par e-mail dans la méthode.

7
Mattgb

J'ai fait ce monstre pour mes propres besoins

CREATE PROCEDURE [dbo].[RequestHttpWebService]
@Url varchar(1024),
@HttpMethod varchar(10),
@ParamsValues varchar(1024),    -- param1=value&param2=value
@SoapAction varchar(1024) = null
AS
BEGIN
SET NOCOUNT ON;

--set @Url = 'http://localhost/service.asmx'
--set @HttpMethod = 'soap'
--set @ParamsValues = 'login=tr2280&password=Qwe12345&domain=webtech.development'
--set @SoapAction = 'Authenticate'


if @HttpMethod in ('get','GET') and len(@ParamsValues) > 0
begin
    set @Url = @Url + '?' + @ParamsValues
end

declare @obj int
    ,@response varchar(8000)
    ,@responseXml xml
    ,@status varchar(50)
    ,@statusText varchar(1024)
    ,@method varchar(10) = (case when @HttpMethod in ('soap','SOAP') then 'POST' else @HttpMethod end)

exec sp_OACreate 'MSXML2.ServerXMLHttp', @obj out
exec sp_OAMethod @obj, 'Open', null, @method, @Url, false

if @HttpMethod in ('get','GET')
begin
    exec sp_OAMethod @obj, 'send'
end
else if @HttpMethod in ('post','POST')
begin
    exec sp_OAMethod @obj, 'setRequestHeader', null, 'Content-Type', 'application/x-www-form-urlencoded'
    exec sp_OAMethod @obj, 'send', null, @ParamsValues
end
else if @HttpMethod in ('soap','SOAP')
begin
    if @SoapAction is null
        raiserror('@SoapAction is null', 10, 1)

    declare @Host varchar(1024) = @Url
    if @Host like 'http://%'
        set @Host = right(@Host, len(@Host) - 7)
    else if @Host like 'https://%'
        set @Host = right(@Host, len(@Host) - 8)

    if charindex(':', @Host) > 0 and charindex(':', @Host) < charindex('/', @Host)
        set @Host = left(@Host, charindex(':', @Host) - 1)
    else 
        set @Host = left(@Host, charindex('/', @Host) - 1)

    declare @envelope varchar(8000) = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><{action} xmlns="http://tempuri.org/">{params}</{action}></soap:Body></soap:Envelope>'
    declare @params varchar(8000) = '' 

    WHILE LEN(@ParamsValues) > 0
    BEGIN
        declare @param varchar(256),
                @value varchar(256)

        IF charindex('&', @ParamsValues) > 0
        BEGIN

            SET @param = left(@ParamsValues, charindex('&', @ParamsValues) - 1)
            set @value = RIGHT(@param, len(@param) - charindex('=', @param))
            set @param = left(@param, charindex('=', @param) - 1)
            set @params = @params + '<' + @param + '>' + @value + '</'+ @param + '>'
            SET @ParamsValues = right(@ParamsValues, LEN(@ParamsValues) - LEN(@param + '=' + @value + '&'))
        END
        ELSE
        BEGIN
            set @value = RIGHT(@ParamsValues, len(@ParamsValues) - charindex('=', @ParamsValues))
            set @param = left(@ParamsValues, charindex('=', @ParamsValues) - 1)

            set @params = @params + '<' + @param + '>' + @value + '</'+ @param + '>'
            SET @ParamsValues = NULL
        END
    END

    set @envelope = replace(@envelope, '{action}', @SoapAction)
    set @envelope = replace(@envelope, '{params}', @params)

    set @SoapAction = 'http://tempuri.org/' + @SoapAction

    print @Host
    print @SoapAction
    print @envelope

    exec sp_OAMethod @obj, 'setRequestHeader', null, 'Content-Type', 'text/xml; charset=utf-8'
    exec sp_OAMethod @obj, 'setRequestHeader', null, 'Host', @Host
    exec sp_OAMethod @obj, 'setRequestHeader', null, 'SOAPAction', @SoapAction
    exec sp_OAMethod @obj, 'send', null, @envelope
end

exec sp_OAGetProperty @obj, 'responseText', @response out
exec sp_OADestroy @obj

select @status as [status], @statusText as [statusText], @response as [response]
END
GO

modifier: mise en forme

3
Arthur

J'ai également rencontré ce problème. Voici la bonne façon d'exécuter une publication HTTP avec des paramètres de T-SQL:

DECLARE @authHeader NVARCHAR(64);
DECLARE @contentType NVARCHAR(64);
DECLARE @postData NVARCHAR(2000);
DECLARE @responseText NVARCHAR(2000);
DECLARE @responseXML NVARCHAR(2000);
DECLARE @ret INT;
DECLARE @status NVARCHAR(32);
DECLARE @statusText NVARCHAR(32);
DECLARE @token INT;
DECLARE @url NVARCHAR(256);

SET @authHeader = 'BASIC 0123456789ABCDEF0123456789ABCDEF';
SET @contentType = 'application/x-www-form-urlencoded';
SET @postData = 'value1=Hello&value2=World'
SET @url = 'https://requestb.in/16xdq1p1'

-- Open the connection.
EXEC @ret = sp_OACreate 'MSXML2.ServerXMLHTTP', @token OUT;
IF @ret <> 0 RAISERROR('Unable to open HTTP connection.', 10, 1);

-- Send the request.
EXEC @ret = sp_OAMethod @token, 'open', NULL, 'POST', @url, 'false';
EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Authentication', @authHeader;
EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Content-type', @contentType;
EXEC @ret = sp_OAMethod @token, 'send', NULL, @postData;

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

-- Show the response.
PRINT 'Status: ' + @status + ' (' + @statusText + ')';
PRINT 'Response text: ' + @responseText;

-- Close the connection.
EXEC @ret = sp_OADestroy @token;
IF @ret <> 0 RAISERROR('Unable to close HTTP connection.', 10, 1);

Le mérite revient à l'auteur original.

Edit: L'exemple de service que j'appelais ici semble s'être arrêté. Vous devrez échanger l'URL et publier sur un autre point de terminaison afin de le voir fonctionner.

2
misteroptimist

Vous ne pouvez pas ajouter une référence Web de la manière habituelle lors de la maintenance d'un projet SQL Server dans Visual Studio. Cependant, vous pouvez utiliser l'utilitaire WSDL pour créer l'interface Web et l'ajouter à votre solution. Par la suite, vous pourrez alors accéder aux méthodes Web que vous souhaitez dans votre procédure stockée CLR.

L'utilitaire WSDL.exe se trouve dans les SDK Microsoft installés, j'ai exécuté le mien en utilisant la version Windows 7 mais une simple recherche de votre disque dur devrait vous donner votre emplacement, qui a été installé dans le répertoire suivant: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin

Les commandes à utiliser lors de l'exécution de l'utilitaire WSDL.exe sont les suivantes:

WSDL.exe /o:(name of Visual Studio Class file) /n:(name of namespace) (address of webservice)

par exemple:

WSDL.exe /o:Weather.cs /n:Weather.Test http://wsf.cdyne.com/WeatherWS/Weather.asmx

Cela va générer un Weather.cs fichier dans cette instance que vous pouvez ensuite ajouter à votre projet et appeler dans votre méthode.

0
Mattgb