Con SQL Server Integration Services è possibile utilizzare un particolare task, chiamato Web service Task, utilizzato proprio per invocare Web services. E' il seguente:
Prendiamo un semplicissimo scenario, il web service di default che
Visual Studio 2005 ci propone quando creiamo un progetto Web Service.
Il classico Hello World.
L'utilizzo del task è molto semplice. Gli step da seguire per poter usufruire delle sue funzionalità sono i seguenti:
- Creare un connection Manager di tipo HTTPNell'esempio ho impostato semplicemente il link http al mio
WSDL di prova, ma come potete notare ci sono altre impostazioni molto importanti da poter utilizzare.
Ad esempio è possibile fornire username, password e dominio di accesso, impostare un certificato, definire il timeout, la dimensione del blocco per la scrittura dei dati e testare la connessione.
In alto vi è anche la clip dedicata alle impostazioni di un eventuale proxy.
Siccome questa connessione HTTP è stata appositamente creata per un web service task e siccome avrò bisogno di conoscere la struttura del servizio, e quindi un WSDL, l'url di riferimento comprende il parametro
?WSDL. Chiamiamolo
Servizio- Creare una variabile che conterrà la risposta (o un connection manager File per scrivere la risposta su filesystem)E' possibile ad esempio creare una variabile di tipo stringa che conterrà la risposta del nostro servizio.
- Creare nella cartella del nostro progetto o su di una posizione nel disco ben definita un file vuoto con estensione .wsdl- Impostare il Web Service Task come segue:Fare doppio click sul Web service Task.
Come prima cosa selezionare la http connection che abbiamo creato pocanzi e poi definire nella proprietà
WSDLFile il percorso ove il file .wsdl è stato creato.
La terza proprietà,
OverwriteWSDLFile, indica se si vuole sovrascrivere il file alla pressione del tasto sottostante, il
Download WSDL.
La prima volta, ed ogni volta che la struttura del servizio cambia (e quindi ogni volta che si vuole scaricare il nuovo WSDL) lasciare questa proprietà impostata a
True.
A questo punto, premere il tasto
Download WSDL e attendere il messaggio di conferma:
Se la proprietà OverwriteWSDLFile è a
False, viene restituito un messaggio di errore.
Facoltativamente, potete andare a controllare sul disco e noterete che il file scaricato è effettivamente il WSDL del servizio che dobbiamo invocare.
- Definire la sezione InputSpostarsi sulla sezione input. Scegliere il servizio (proprietà
Service) ed il metodo da eseguire (proprietà
Method). Nel caso in cui il metodo abbia parametri, comparirà un'apposita sezione al di sotto della selezione della chiamata. Qui di seguito un esempio di chiamata con un parametro stringa (metodo Message), mentre quello al precedente punto non ne ha alcuno:
Attenzione, perchè per i tipi che non sono considerati primitivi, come possono esserlo interi e stringhe, SSIS non è in grado di fornire il passaggio di parametri. Ad esempio, un metodo definito come il seguente, non restituirà a SSIS nessuna richiesta di parametri input:
<WebMethod()> _
Public Function
NumeroRighe(ByVal ds As
DataSet) As Integer
Return
ds.Tables(0).Rows.Count
End Function
- Definire la sezione OutputDopo aver configurato l'input, definiamo l'output selezionando il tipo di container della risposta, File o Variabile. Qui di seguito l'esempio su variabile, dichiarata all'inizio del post:
Eseguendo un ipotetico SSIS che lancia il web service suddetto e che in seguito visualizza il valore della risposta avremo questo comportamento:
Dopo aver introdotto il task, vorrei soffermarmi su alcuni ostacoli che potremmo incontrare nell'usarlo. E vorrei anche giustificare il titolo del post
.
Oltre a non poter passare parametri di un certo tipo (da MSDN: "
The Web Service task supports parameters of the following data types
only: primitive types such as integers and strings; arrays and
sequences of primitive types; and enumerations."), vi è da ricordare che tutte le risposte del web service task sono stringhe. Ognuna di esse è la serializzazione del valore/oggetto di ritorno. Quindi ogni stringa contiene l'XML della risposta serializzata. Questo perchè il task non si pone di creare una classe proxy come ad esempio Visual Studio fa quando aggiungiamo una Web Reference.
Abbiamo la possibilità di salvare la stringa su un file xml, è vero, ma se volessimo utilizzare la risposta tipizzandola e castandola in un nostro oggetto all'interno di un package, dovremmo per forza ricorrere alla deserializzazione. E quindi scrivere codice.
Di conseguenza, molto spesso non utilizzo il web service task ma direttamente lo script task, in un modo un po' particolare.
Tramite il tool WSDL.exe usato anche da Visual studio per scrivere la classe proxy dal wsdl, genero la classe proxy.
Aggiungo uno script task e includo al suo interno la classe generata con wsdl.exe (con SSIS 2005 solo VB). Inoltre aggiungo il riferimento a
System.Web.Services e
System.Xml.
Nello ScriptMain possiamo istanziare il manager del servizio (la nostra classe proxy) per eseguire i metodi da codice. Ricordiamo il metodo d'esempio:
<WebMethod()> _
Public Function
NumeroRighe(ByVal ds As
DataSet) As Integer
Return
ds.Tables(0).Rows.Count
End Function
Ecco come nello Script eseguo la chiamata:
Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Runtime
Public Class ScriptMain
Public Sub Main()
' istanzio il web service
Dim objWS As New Service1()
' creo una tabella con una riga
Dim objdt As New DataTable()
objdt.Columns.Add("col1", GetType(System.String))
Dim objdr As DataRow
= objdt.NewRow()
objdr("col1") = "PROVA"
objdt.Rows.Add(objdr)
' popolo il dataset
Dim objDs As New DataSet
objDs.Tables.Add(objdt)
' chiamo il metodo che mi torna il numero di righe della tabella del
dataset
Dim i As Integer =
objWS.NumeroRighe(objDs)
' ...
Dts.TaskResult = Dts.Results.Success
End Sub
End Class
Con questo metodo possiamo muoverci con maggiore libertà sui tipi del framework ed anche su quelli definiti da noi. Esiste comunque un rovescio della medaglia, ed è quello relativo alla manutenzione del codice. Cambiando la struttura del web service, è necessario replicare la nuova classe proxy anche negli script che la utilizzano.
ATTENZIONEVi è una soluzione più
corretta, ovvero
creare una dll strongly signed e metterla in GAC, in modo tale da poter aggiungere il riferimento così come per le altre classi .NET. Quest'ultima è sicuramente la soluzione più pulita, se non vogliamo utilizzare il task di SSIS. Ad ogni modo, il riferimento deve essere aggiunto a livello di Script poichè non è possiible referenziare una DLL a livello globale.
Comunque lascio la firma e la creazione dell'assembly in GAC a Voi.. ecco un link utile per capire meglio come firmare la dll
http://msdn2.microsoft.com/en-us/library/ms247123.aspx
Stay tuned!