Technology Experience
.NET World

Ottenere l’ID dell’ultimo file uploadato – optimized version

Introduzione
Lunedì pomeriggio ho scritto un post in cui facevo vedere come usare la chiamata al metodo GetListItems del web-service /_vti_bin/lists.asmx di Sharepoint per ottenere l’elenco dei files pubblicati in una document library. Lo scopo era quello di reperire l’ID univoco dell’ultimo file uploadato – file di cui vogliamo aggiornare i metadati. Il mio ragionamento era il seguente:

  1. ottengo l’elenco completo di tutti i files pubblicati
  2. faccio il parsing dell’XML restituito dal web-service
  3. ciclo su tutti i files restituiti, fino a quando non trovo quello che mi interessa.

Controindicazioni
Questo approccio – fondamentalmente corretto – presenta però qualche problema, come giustamente ha osservato mio fratello nel commento che mi ha lasciato nel suddetto post. Per prima cosa, genero più traffico http del dovuto: io ho bisogno di sapere solo l’ID di un solo file, mentre così facendo l’XML contiene tutto l’immaginabile relativo ad una document library.

CAML: cosa diavolo è?
Con la sua osservazione, Omar mi ha fatto conoscere un nuovo acronimo: CAML. L’acronimo sta per Collaborative Application Markup Language, e – come dice il nome – è un XML particolare da “dare in pasto” al web-service. Tramite CAML possiamo filtrare ed ordinare sui campi di una document library. Va da sè quindi che possiamo ottimizzare molto la ricerca che facciamo, dicendo per esempio di escludere le directory e di ordinare in base al campo ID in modo decrescente. L’ultimo file uploadato otterrà sempre l’ID più alto, e quindi…

Ok. Dopo averci litigato un po’, ieri sera ho raggiunto la soluzione. Il codice CAML che dobbiamo scrivere per trovare l’ID del file è la seguente:

<OrderBy> <FieldRef Name="ID" Ascending="False" /> </OrderBy> <Where> <Neq> <FieldRef Name="ContentType" /> <Value Type="Text">Folder</Value> </Neq> </Where>

Il blocco <OrderBy></OrderBy> esprime ovviamente l’ordinamento, che avviene per ID in modo decrescente (grande –> piccolo). Il blocco <Where></Where> esprime eventuali filtri (inclusivi od esclusivi) da applicare alla ricerca. In questo caso, diciamo che il campo ContentType NON deve essere uguale (operatore Neq) a Folder.

Non di solo CAML vivrà la mia applicazione!

CAML deve essere eseguito sul server WSS per fornire un risultato. Io lo eseguo con C#, voi fate un po’ come volete.

Ho riscritto praticamente da zero il metodo ReadFileID che avevo pubblicato lunedì. La versione attuale è la seguente:

1 public void ReadFileID(string listName, string fileName) 2 { 3 Lists l = new Lists(); 4 l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain); 5 6 XmlDocument doc = new XmlDocument(); 7 XmlNode query = doc.CreateNode(XmlNodeType.Element, "Query", string.Empty); 8 9 string xml = ResourceHelper.GetResourceContent("UploaderMOSS.XML.ListQuery.xml"); 10 11 XmlNode node = l.GetListItems(listName, null, query, null, "1", null, null); 12 13 node = node.FirstChild.NextSibling.FirstChild.NextSibling; 14 15 this.CacheFilesID.Add(fileName, node.Attributes["ows_ID"].Value); 16 }

Riga (3) e (4): istanzio il web-service con le credenziali corrette.

Riga (6) e (7): creo un XmlDocument e creo il nodo <Query></Query>. All’interno di questi tag viene messo il blocco CAML visto sopra, riga (9). Ecco perchè non ho messo <Query></Query> direttamente nel CAML: preferisco farlo via C# ed innestare il CAML nel nodo creato a riga (7).

Riga (11): lancio la chiamata al metodo GetListItems. I parametri sono: il nome della lista (in chiaro), il nome della view (opzionale, in chiaro), l’oggetto query, un blocco XAML per i fields da vedere, il row-count, un blocco XAML per le query options, ed il WebID (opzionale?). Notare che – al contrario di quanto facevo con la vecchia versione – qui il row-count è messo a “1”.

Il resto non è nulla di che: navigo nell’XMLNode restituito dal web-service ed aggiungo alla cache privata della classe l’ID che abbiamo chiesto. Il metodo potrebbe aggiungerlo alla cache e restituirlo al chiamante, che forse sarebbe più comodo. Sono scelte: io l’ho fatto così.

Eventuali problemi

Nei giorni scorsi io ho avuto parecchi problemi ad utilizzare questa tecnica. Secondo me, dovete tener ben presente le seguenti cose:

  1. occhio a come create il CAML. Se non state attenti, potrà capitarvi di annidare un nodo <Query> dentro un nodo <Query>, e questo ovviamente al run-time di WSS non piace molto. Lo stesso vale per tutto il resto della query.
  2. il campo ID deve essere numerico, altrimenti – lo sapete meglio di me – l’ordinamento va a pallino. Sembra uno scherzo, ma io ho una document library con un campo ID che non viene ordinato nel modo corretto. Deduco che non sia numerico, ma non riesco a capirlo. Se non ci credete, eccola qua…

Send to Kindle

Igor Damiani

La sua passione per l'informatica nasce nella prima metà degli anni '80, quando suo padre acquistò un Texas Instruments TI-99. Da allora ha continuato a seguire l'evoluzione sia hardware che software avvenuta nel corso degli anni. E' un utente, un videogiocatore ed uno sviluppatore software a tempo pieno. Igor ha lavorato e lavora anche oggi con le più moderne tecnologie Microsoft per lo sviluppo di applicazioni: .NET Framework, XAML, Universal Windows Platform, su diverse piattaforme, tra cui spiccano Windows 10 piattaforme mobile. Numerose sono le app che Igor ha creato e pubblicato sul marketplace sotto il nome VivendoByte, suo personale marchio di fabbrica. Adora mantenere i contatti attraverso Twitter e soprattutto attraverso gli eventi delle community .NET.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.