Sharepoint Web Services. Quali usare per interagire con le liste?
Sharepoint Web Services. Quali usare per interagire con le liste?
Sharepoint (WSS ed SPS) mette a disposizione un nutrito numero di Web Services che permettono di accedere a quasi tutte le funzionalità offerte dall’Objet Model nativo .NET.
Come ben saprete l’Object Model nativo di Sharepoint è accessibile solo se il programma chiamanante gira su una macchina dove è installato Sharepoint (WSS o SPS).
Se dovete usare le funzionalità di Sharepoint da remoto dovete obbligatoriamente ricorrere ai Web Services. Nulla di male in fondo no? Siamo o non siamo all’alba del nuovo mondo orientato alle architetture SOA? Quindi nessuna paura ed andiamo avanti con fiducia.
L’interazione più frequente è quella con le liste ed il loro contenuto. Ricordo che le librerie documenti e le liste sono programmaticamente parlando derivate dalla stessa classe, SPList e che esse sono composte da elementi di lista derivati dalla stessa classe, SPListItem inclusi in insiemi denominati SPListItems.
Il problema dei Web Services di Sharepoint è che quando si parla di List, ListItems e ListItem ci sono almeno TRE Web Services che in perfetta logica Microsoft offrono accesso a questi oggetti: Lists, SiteData e StsAdapter.
Il dilemma diventa pressante: quale usare?
La risposta del DevGuro di turno è come al solito, la solita:
"Dipende da quello che ci si deve fare con la lista."
Questa ovvia e banale risposta nasce dalla saggezza del DevGuro J
Come ha fatto il DevGuro a dare un cotanto illuminato a saggio consiglio?
Ma è ovvio: studiando il comportamento dei Web Services in questione.
Il primo Web Service è Lists.
E’ documentato a questa URL
http://Server_Name/[sites/][Site_Name/]_vti_bin/Lists.asmx
Lists, lo dice il nome, serve per interagire con gli oggetti di classe List, anzi come dice il testo sacro (l’SDK di Sharepoint):
"The Lists service provides methods for working with lists and list data"
Tenete bene a mente il "Working" ed il significato che gli Anglosassoni danno al verbo "To Work".
Contiene dei metodi che permettono di Creare, Aggiornare, Cancellare ed ottenere le informazioni relative alle liste ed agli elementi di lista.
<Apro una parentesi.>
Per i più inesperti dico subito che questo Web Service NON CONTIENE NESSUN METODO per effettuare l’upload di un documento in una document library.
Dirò anche che non esiste nessun Web Service che offre questo metodo per le liste di tipo document library. Con AddAttachment potete fare l’upload di allegati in liste di tutti i tipi tranne che in quelle di tipo document library. Il motivo non è ben chiaro. Io sospetto che il motivo sia stata pura dimenticanza da parte del team di sviluppo J. A conforto di questa tesi l’esistenza del metodo Upload offerto dal Web Service Imaging, dedicato alla gestione delle liste di tipo Immagine.
</Chiusa la parentesi.>
Il secondo Web Service è SiteData.
E’ documentato a questa URL
http://Server_Name/[sites/][Site_Name/]_vti_bin/SiteData.asmx
Secondo l’SDK SiteData offre metodi per ottenere informazioni (dati e metadati) circa siti, liste e gli elementi in esse contenuti.
Infatti la documentazione recita testualmente:
"The Site Data service provides methods that return metadata or list data from sites or lists in Microsoft Windows SharePoint Services."
Ultimo Web Service che in qualche maniera lavora con le liste (e che ci interessa osservare in questa breve disquisizione) è StsAdapter.
E’ definito in questa URL:
http://Server_Name/[sites/][Site_Name/]_vti_bin/DspSts.asmx
StsAdapter (o List Data Retrieval Service) espone un solo metodo: Query.
Insomma StsAdapter serve per effettuare delle ricerche nelle liste di un sito Windows Sharepoint Service. I siti Sharepoint Portal Server possono far affidamento su un sistema di interrogazione ben più potente. Tuttavia in questa sede parliamo solo di Windows Sharepoint Services.
Iniziamo a guardare in poco questo tre Web Services.
Quello che si nota subito è che Lists e SiteData hanno due metodi in comune denominati GetList e GetListItems che apparentemente fanno la stessa cosa. Anche StsAdapter in fin dei conti con il suo metodo Query offre gli stessi servizi dei metodi GetListItems.
In realtà i metodi GetList fanno la stessa cosa sulle liste cosi come i metodi GetListItem e Query fanno le stesse cose sugli elementi di lista, solo che lo fanno in maniera lievemente diversa. Differiscono per la qualità/quantità delle informazioni che richiedono come parametri e che forniscono come risultati.
Analizziamo sommariamente le dichiarazione dei metodi Lists.GetList e SiteData.GetList:
Lists.GetList accetta un solo parametro in input, ListName, che è una stringa contenente o il nome della lista o il suo GUID (tralascio il caso in cui si interroghi la lista degli utenti del sito). Ritorna come valore della chiamata un frammento XML (una stringa) contenente lo schema della lista secondo le convenzioni del CAML (il dialetto XML di Sharepoint)
SiteData.GetList vuole il passaggio di tre paramenti:
ListName, che è una stringa contenente il nome della lista o il suo GUID in input.
ListMedatata, una stringa passata per riferimento che conterrà i metadati della lista (nome, creazione, creatore, vista di default etc) secondo il formato previsto dalla definizione di classe _sListMetadata presente nel Web Service.
Properties, che è un array di stringhe contenente l’elenco dei campi con i tipi dati secondo la definizione data dalla classe _sProperty presente nel Web Service.
Ritorna come valore 0 ad indicare che la chiamata ha avuto successo.
Le differenze fra Lists.GetList e SiteData.GetList sono quindi nella qualità dei risultati forniti: Lists.GetList fornisce un frammento XML (CAML) con TUTTE le informazioni possibili sulla struttura della lista e dei campi in essa definiti, mentre SiteData.GetList fornisce i dati in un formato direttamente usabile dal programmatore.
Un esempio reale chiarirà la differenza d’uso
Invocazione di Lists.GetList e suo output
Dim listService As New Web_Reference_Folder_Name.Lists()
listService.Credentials = System.Net.CredentialCache.DefaultCredentials
Dim ndLists As XmlNode = listService.GetList("List_Name")
MessageBox.Show(ndLists.OuterXml)
XML prodotto:
<List DocTemplateUrl="" DefaultViewUrl="/Site_Name/Lists/List_Name/AllItems.aspx"
ID="{42FC00F1-F7EA-4ECE-9D4C-F47A95A806B2}" Title="List_Name" Description="Description"
ImageUrl="/_layouts/images/itgen.gif" Name="{42FC00F1-F7EA-4ECE-9D4C-F47A95A806B2}"
BaseType="0" ServerTemplate="100" Created="20030616 18:37:44" Modified="20030618 18:26:57"
LastDeleted="20030616 18:37:44" Version="2" Direction="none" ThumbnailSize="" WebImageWidth=""
WebImageHeight="" Flags="4096" ItemCount="5" AnonymousPermMask=""
RootFolder="/Site_Name/Lists/List_Name" ReadSecurity="1" WriteSecurity="1"
Author="1" EventSinkAssembly="" EventSinkClass="" EventSinkData="" EmailInsertsFolder=""
AllowDeletion="True" AllowMultiResponses="False" EnableAttachments="True" EnableModeration="False"
EnableVersioning="False" Hidden="False" MultipleDataList="False" Ordered="False" ShowUser="True"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Fields>
<Field ColName="tp_ID" ReadOnly="TRUE" Type="Counter" Name="ID" PrimaryKey="TRUE"
DisplayName="ID" FromBaseType="TRUE" />
<Field Type="Text" Name="Title" DisplayName="Title" Required="TRUE" FromBaseType="TRUE"
ColName="nvarchar1" />
.
.
.
<Fields>
<RegionalSettings>
<Language>1033<Language>
<Locale>1025<Locale>
<CalendarType>6<CalendarType>
<AdvanceHijri>-1</AdvanceHijri>
<TimeZone>1</TimeZone>
<Time24>1</Time24>
<SortOrder>1033<SortOrder>
<Presence Enabled="True" />
</RegionalSettings>
</List>
Invocazione di SiteData.GetList
Dim srvSiteData As New Web_Reference_Folder_Name.SiteData()
srvSiteData.Credentials = System.Net.CredentialCache.DefaultCredentials
Dim lstMetaData As Web_Reference_Folder_Name._sListMetadata
Dim lstFields() As Web_Reference_Folder_Name._sProperty
srvSiteData.GetList("List_Title", lstMetaData, lstFields)
label1.Text = lstMetaData.Title + " :: " + lstMetaData.DefaultViewUrl + ControlChars.Lf
Dim field As Web_Reference_Folder_Name._sProperty
For Each field In lstFields
label1.Text += field.Title + " :: " + field.Name + " :: " + field.Type + ControlChars.Lf
Next field
Senza essere dei DevGuri è chiara la differenza fra i due metodi: Lists.GetList fornisce il massimo dettaglio sulla struttura della lista e la massima usabilità del Web Service secondo la filosofia dei Web Services mentre SiteData.GetList fornisce un risultato già predigerito per essere usato As-is nei programmi e soprattutto in ambiente .NET.
Eh già, perché se non avete .NET o un client SOAP capace di gestire tipi complessi potete scordarvi di usare il Web Service SiteData rassegnarvi ad usare Lists e ricorrere al DOM dell’XML.
Veniamo ora a Lists.GetListsItem, SiteData.GetListItems e StsAdapter.Query.
Qui le cose si complicano ancora mostrando l’eccezionale coerenza degli architetti di Sharepoint (sto ovviamente scherzando…) nella definizione dei prototipi di funzione!
Lists.GetListItems ha molti parametri in ingresso
ListName: è il nome della lista o il suo GUID.
ViewName: è il nome della vista (come saprete le liste possono avere n viste). Se omettere il nome della lista viene assunta la lista di default.
Query: è un frammento XML che contiene la query in simil-SQL. Equivale alla WHERE dell’SQL.
Esempio:
<Query>
<Where>
<Lt>
<FieldRef Name="ID" />
<Value Type="Counter">3</Value>
</Lt>
</Where>
</Query>
ViewFields: è un frammento XML che contiene l’elenco dei campi che si intendono includere nel set di risultato. E’ equivalente all’elenco dei campi dello statement SELECT .
Esempio:
<ViewFields>
<FieldRef Name="ID" />
<FieldRef Name="Title" />
</ViewFields>
RowLimit: è una stringa che contiene il numero massimo di righe che si vogliono avere nel set di dati risultante. Se ci mettete "0" otterrete tutte le righe.
QueryOptions: è un frammento XML che contiene le opzione di esecuzione della query.
Esempio:
<QueryOptions>
<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>
<DateInUtc>TRUE</DateInUtc>
</QueryOptions>
Una interessante opzione disponibile è quella del meccanismo di paginazione fornito dal nodo "Paging" e dall’attributo "ListItemCollectionPositionNext". Dico solo che questo nodo ed il relativo attributo permettono di effettuare una richiesta paginata del set di dati direttamente al server. Utile quando le righe ritornate sono migliaia.
Il risultato fornito da Lists.GetListItems è pure lui un frammento XML. Ecco un esempio di quanto il metodo ci restituisce:
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="4">
<z:row ows_Number_Field="6555.00000000000" ows_Created="2003-06-18T03:41:09Z"
ows_ID="3" ows_owshiddenversion="3" />
<z:row ows_Number_Field="78905456.0000000" ows_Created="2003-06-18T17:15:58Z"
ows_ID="4" ows_owshiddenversion="2" />
.
.
.
</rs:data>
</listitems>
SiteData.GetListItems richiede un po meno parametri
ListName: è il GUID della lista (GUID, NON nome, solo GUID)
Query: è un frammento XML che contiene la query in simil-SQL. Equivale alla WHERE dell’SQL. Sembra apparentemente simile a quello di Lists.GetListItems ma a differenza di questo non include il nodo "<Query>"
Esempio:
<Where>
<Lt>
<FieldRef Name="ID" />
<Value Type="Counter">3</Value>
</Lt>
</Where>
ViewFields: è un frammento XML che contiene l’insieme di campi che verranno inclusi nel set dei risultati. A differenza dell’equivalente paramentro di Lists.GetListItems non è racchiuso in un nodo "<ViewFields>"
Esempio:
<FieldRef Name="ID" />
<FieldRef Name="Title" />
RowLimit: è un intero che contiene il numero massimo di righe da tornare
Questo è il risultato del metodo SiteData.GetListItems, ovvero un frammento XML
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly" rs:CommandTimeout="30">
<s:AttributeType name="ows_Title" rs:name="Title" rs:number="1">
<s:datatype dt:type="string" dt:maxLength="512" />
</s:AttributeType>
<s:AttributeType name="ows_Number" rs:name="Number" rs:number="2">
<s:datatype dt:type="float" dt:maxLength="8" />
</s:AttributeType>
<s:AttributeType name="ows_ID" rs:name="ID" rs:number="3">
<s:datatype dt:type="i4" dt:maxLength="4" />
</s:AttributeType>
<s:AttributeType name="ows_owshiddenversion" rs:name="owshiddenversion" rs:number="4">
<s:datatype dt:type="i4" dt:maxLength="4" />
</s:AttributeType>
</s:ElementType>
</s:Schema>
<rs:data ItemCount="1">
<z:row ows_Title="Value1" ows_Number="100.000000000000" ows_ID="1" ows_owshiddenversion="2" />
<z:row ows_Title="Value2" ows_Number="100.000000000000" ows_ID="2" ows_owshiddenversion="2" />
.
.
.
</rs:data>
</xml>
Le differenze sono meno evidenti rispetto ai metodi GetList visti precedentemente ma comunque significativi.
SiteData.GetListItems è poco più semplice da invocare rispetto a Lists.GetListItems ma non fornisce vantaggi o semplificazioni per l’interazione dei dati forniti, anzi complica la vita al programmatore in quanto richiede la spccifica del GUID della lista e non solo il suo nome. SiteData.GetListItems non fornisce nessun meccanismo di Paging o di definizione delle opzioni di query.
StsAdapter.Query invece è un metodo specifico per l’esecuzione delle query nelle liste di Sharepoint. E’ più orientato alla ricerca vera e propria e non è decisamente ben documentato nella versione corrente dell’SDK.
sabato, 11 feb 2006 Ore. 00.15