Technology Experience

.NET World

Programmazione, libri, snippet di codice, articoli tecnici

.NET World

Aggiornamenti su VivendoByte Technorati Tags

Ogni tanto vi tedio parlandovi del plug-in per Windows Live Writer che mi sono scritto in WPF per poter “compilare” velocemente i tags con cui marcare i post che poi finiscono dritti dritti sul mio blog. Ricordo che questo plug-in fa parte di una piccola suite che ho pubblicato su CodePlex: i sorgenti sono pubblici e tutti voi potete utilizzarlo. Anzi, se mi trovate qualche baco, segnalatemelo!

Ve ne parlo perchè nel frattempo qualcosa è cambiato. Vediamo di spiegare cosa e perchè.

L’elenco di tags che il plug-in vi mostra arriva direttamente dal web-service esposto da Technorati.com. Questo web-service chiede in input l’url di un blog e restituisce una List<string>: fino alle precedenti versioni questa lista veniva bindata ad una ListBox di WPF per poter essere selezionate dall’utente.

Ho deciso di non utilizzare più stringhe, ma di creare una classe ad-hoc TechnoratiTag. Prima di potervi spiegare il perchè, occorre breve una premessa, relativa alle vecchie versioni del plug-in:

  1. se il PC su cui gira il plug-in risultava essere connesso alla Rete, allora l’elenco dei tags veniva preso da Technorati come spiegato prima
  2. se il PC su cui gira il plug-in NON risultava essere connesso alla Rete, l’elenco dei tags veniva preso da un file locale di cache, salvato in C:Documents and SettingsIgorDati applicazioniVivendoByte Technorati Tags.

Il web-service di Technorati restituisce i 100 tag più utilizzati: se per caso ne inserivate uno a mano – non compreso nell’elenco – ve lo perdavate alla grande: il tag veniva salvato effettivamente sulla cache locale, ma in realtà non veniva più proposto, proprio perchè la cache locale veniva ignorata se eravate connessi alla Rete.

Ho quindi pensato che la cosa migliore fosse quella di creare una List<TechnoratiTag>, che fosse l’unione dei tags presi da Technorati e presi dalla cache locale. La classe TechnoratiTag è così composta:

public class TechnoratiTag { private TagSource _source; private string _identifier; public TagSource Source { get { return _source; } set { _source = value; } } public string Identifier { get { return _identifier; } set { _identifier = value; } } }

La proprietà TagSource è un semplice enum che distingue i tags provenienti dalla Rete (TagSource.Internet) oppure dalla cache locale (TagSource.LocalDisk). L’implementazione del metodo LoadTags() del mio repository service è la seguente:

1 public List<TechnoratiTag> LoadTags() 2 { 3 List<TechnoratiTag> internetTags = null; 4 List<TechnoratiTag> localTags = null; 5 List<TechnoratiTag> tags = new List<TechnoratiTag>(); 6 7 if (TestInternetAvaiableService.TestInternetAvaiable()) 8 internetTags = this.LoadRemoteTags(); 9 10 localTags = this.LoadLocalTags(); 11 12 if (internetTags != null) 13 tags.AddRange(internetTags); 14 15 if (localTags != null) 16 foreach (TechnoratiTag t in localTags) 17 { 18 criteria = t.Identifier; 19 if (!tags.Exists(new Predicate<TechnoratiTag>(findTechnoratiTag))) 20 tags.Add(t); 21 } 22 23 tags.Sort(sortTechnoratiTag); 24 25 return tags; 26 }

Alle righe 7 ed 8 vengono caricati i tags dal web-service di Technorati. Alla riga 10 vengono caricati i tags dalla cache locale. Questi due elenchi vengono fusi in un unico List<Technorati> alle linee 15-21, escludendo con una opportuna logica i doppioni. Il tutto viene ordinato e restituito al chiamante.

Il risultato finale è che la ListBox di WPF non viene più bindata da un elenco di stringhe, ma ad un elenco di TechnoratiTag. Ecco uno screenshot:

Grazie ad un DataTemplateSelector viene applicato un template diverso a seconda del valore di ciascun TagSource: i tag che arrivano da Internet hanno un’iconcina con il globo, mentre quelli che arrivano dalla cache locale hanno un’iconcina del CD. In questo modo anche tag poco usati, che magari Technorati non vi segnalerebbe, compaiono magicamente nella lista!

Installazione

Oltre che su CodePlex, il download diretto dei binari è disponibile qui : Windows Live Writer Plugins Technorati Tags WPF. E’ sufficiente aprire il file zip e dezippare il tutto in C:ProgrammiWindows LiveWriterPlugins.

Technorati Tags:    

Send to Kindle
.NET World

Uploader for Windows Sharepoint Services on CodePlex

Siccome c’è qualcuno interessato, oggi ho deciso di pubblicare su CodePlex il tool che ho scritto nelle settimane precedenti, Uploader for Windows Sharepoint Services. Nome prolisso come è il mio stile.

L’url dove trovare il tutto è questo.

Ci ho messo un po’ per pubblicarlo, ho dovuto ritagliarmi il tempo tra impegni di lavoro attuali e passati, tra vita privata e lavorativa e senza disdegnarne qualche giro (virtuale) a Curitiba in Brasile.

Ho ripulito il codice, ho tolto le informazioni sensibili (spero!) e ho messo on-line il tutto. Come ho già avuto modo di dire, si tratta di un tool che utilizzo anche io in prima persona, perciò state sicuri che il minimo bug verrà corretto e fixato. Se non da me, allora da chiunque vorrà scaricarsi il progetto e ricompilarlo.

Caratteristiche principali del progetto:

  1. creato con Windows Forms
  2. si connette ad un’istanza di Sharepoint tramite web-services per uploadare files
  3. possibilità (più o meno già pronta) di aggiornare i metadati della document library
  4. possibilità di richiamare il tool dal classico SendTo offerto da Windows (comodo!)
  5. multithreading per non bloccare l’interfaccia utente
  6. da oggi è open-source!

Mi piacerebbe in futuro poter creare una feature interessante, cioè quella di sincronizzare un intero folder locale con una document library. Non come adesso…dove si lavora con un file alla volta. Chi vivrà, vedrà!

Technorati Tags:     

Send to Kindle
.NET World

Uno UserControl per esprimere url su Sharepoint

Tanto, tanto tempo fa, in un blog lontano lontano, mi è capitato di leggere questo post di Ayende insieme a tutti i suoi 16 commenti. Ayende si dimostra molto critico nei confronti della finestra di dialogo che permette a Visual Studio di connettersi ad un’istanza di TFS.
La riporto qui per chiarezza:

La criticità è dovuta al fatto che vengono utilizzati più controlli per separare quella che in realtà è un’unica informazione. Un’url, in questo caso. Nei vari commenti si ragiona proprio su questo: mentre un utente esperto potrebbe inserire direttamente https://tfs03.codeplex.com:443, oppure qualsiasi altra cosa, una UI come quella riportata sopra permetterebbe anche al più neofita di fare la stessa cosa.

Poi ho pensato al mio tool, UploaderWSS, di cui ho parlato in qualche mio post precedente. Ho dato un’occhiata all’unica Windows Form inserita nel progetto:

Anche qui, ho dovuto (e voluto) adattare la UI perchè mi servespezzettarel’url nelle diverse componenti in cui può essere suddiviso. Quando si parla di una document library di Sharepoint, le componenti che ho identificato sono le seguenti:

  • server Windows Sharepoint Services
  • website
  • document library
  • folder

Prendiamo un url più complesso per chiarire le cose:

enjoy.vivendobyte.net/sample1/sample2/sample3/sample4

La prima parte è sicuramente il server a cui connettersi. Le altre parti dell’url (sample1, sample2 e via dicendo) sono ignote, perchè non possiamo sapere se si tratta di nomi che identificano websites, document library o folder. Ricordo che all’interno di un server Sharepoint, possiamo annidare un website dentro l’altro, quindi è necessario che l’utente dica espressamente come è composto l’url, altrimenti non sappiamo come procedere. Ad esempio, sample1 può essere il nome di un website, oppure il nome di una document library. Stessa cosa per gli altri elementi. sample3 e sample4 potrebbero essere folder dentro la document library sample2: chi lo sa? sample1, sample2 e sample3 potrebbero essere tre websites annidati, e sample4 il nome di una document library: chi lo sa?

Lo sa solo l’utente finale, e quindi ho creato uno UserControl particolare che appare così:

Lo UserControl incorpora una TextBox al di sotto della quale vengono creati tanti Button quante sono le parti in cui può essere suddiviso l’url. Il separatore è chiaramente lo slash (/). Ogni volta che viene aggiunta una parte di url, viene aggiunto un Button. Ogni volta che uno slash viene rimosso, anche il Button sparisce. Premendo il Button compare un ContextMenu che permette all’utente di specificare che tipo è la parte di url su cui si è cliccato.

Siccome è più semplice da far vedere che da spiegare a parole, ne ho fatto un video su YouTube.

Technorati Tags:   

Send to Kindle
.NET World

Uploader Windows Sharepoint Services

I cinque post che ho scritto nelle settimane scorse su Sharepoint non sono solo dovute allo studio e alla voglia di imparare Sharepoint da un punto di vista dello sviluppatore, ma mi sono serviti anche per sviluppare un tool, che ho battezzato Uploader Windows Sharepoint Services. Uno screenshot lo potete vedere qui sotto.

Questo tool permette l’upload di un file locale in una document library di Sharepoint. E’ ovviamente possibile impostare numerosi parametri, più o meno necessari:

  1. server WSS
  2. info per l’autenticazione (dominio, username e password)
  3. path del file locale
  4. nome del website, nome della document library e path remoti
  5. un campo notes per aggiornare i metadati sulla document library

La cosa secondo me interessante è che è possibile inviare un file semplicemente cliccandoci sopra con il pulsante destro, come si vede dallo screenshot qui sotto.

Non ho ancora reso pubblico nulla, perchè per adesso lo utilizzo io a scopo personale, ma se dovesse essere utile, fatemelo sapere. Lo purifico di tutte le informazioni personali e ne metto i sorgenti da qualche parte.

Comunque sia, è davvero comodo, perchè adesso se voglio mettere qualcosa su Sharepoint non devo più aprire un browser e fare tutte le operazioni necessarie. Basta trovare il file sul mio PC e compilare qualche TextBox. Molto più veloce e pratico!

Technorati Tags:    

Send to Kindle
.NET World

Sharepoint: quali campi possiamo usare nel CAML ?

Una query CAML può far riferimento ad un gran numero di campi, sia per effettuare ordinamenti, sia per applicare filtri. Inizialmente pensavo che il nome di questi campi potesse essere trovato semplicemente sfogliando la document library da Internet Explorer. In realtà quello che si legge nelle ColumnHeaders navigando un website Sharepoint è il Display Name. Nelle query CAML bisogna far riferimento ai campi attraverso il loro Internal Name.

Dove trovare questo famigerato Internal Name? Il buon Vincent Rothwell, MCTS di Sharepoint, ha redatto sul suo blog questa bella tabella HTML che elenca Display Name, Internal Name, Guid e Type dei campi di una Document Library. Basta sfogliarla, trovare il campo desiderato e riportare il tutto nella query CAML.

Technorati Tags:   

Send to Kindle
.NET World

Sharepoint: Ottenere l’ID di un file pubblicato in una document library

Attraverso CAML possiamo fare tutta una serie di query che vanno ad interrogare il contenuto di una document library. Per esempio, se volessimo aggiornare i metadati di un file pubblicato in una document library dobbiamo prima averne l’ID univoco. Questo lo abbiamo visto precedentemente, quando abbiamo ottenuto l’ID dell’ultimo file uploadato.

Quale CAML dobbiamo scrivere per sapere l’ID di un qualsiasi file?
E’ molto semplice:

<Where> <Eq> <FieldRef Name="FileLeafRef" /> <Value Type="Text">{0}</Value> </Eq> </Where>

Se usiamo questo CAML in un metodo GetIDFromFilename, il risultato è servito:

1 public int GetIDFromFilename(string listName, string folder, 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 XmlNode options = doc.CreateNode(XmlNodeType.Element, "QueryOptions", string.Empty); 9 10 if(!string.IsNullOrEmpty(folder)) 11 options.InnerXml = string.Format("<Folder>{0}</Folder>", folder); 12 13 string xml = ResourceHelper.GetResourceContent("UploaderMOSS.XML.GetIDFromFilenameQuery.xml"); 14 query.InnerXml = string.Format(xml, fileName); 15 16 XmlNode node = l.GetListItems(listName, null, query, null, "1", options, null); 17 18 node = node.FirstChild.NextSibling.FirstChild.NextSibling; 19 20 if (node != null) 21 { 22 int idFile = Int32.Parse(node.Attributes["ows_ID"].Value); 23 this.CacheFilesID.Add(fileName, idFile); 24 return idFile; 25 } 26 else 27 return 0; 28 }

I parametri richiesti in input dal metodo sono, nell’ordine: il nome della lista, il path ed il nome del file. Il risultato è un banale int, che può valere 0 (zero) nel caso in cui chiediamo l’ID di un file che non esiste. Se il file è alla root della document library, il parametro folder può essere string.Empty. La query CAML che abbiamo visto prima viene utilizzata alle righe 13 e 14.

Se il file si trova annidato in diversi subfolders della document library, dobbiamo utilizzare – come già ho detto prima – il parametro folder. Internamente, il metodo costruisce un blocco <QueryOptions><Folder>{0}</Folder></QueryOptions>, dove viene iniettato il path (es: “Folder1/Folder2/Folder”, escludendo il nome del file). Questo blocco <QueryOptions> viene passato al metodo GetListItems del web-service di cui vi ho parlato nei post precedenti.

Conclusione

Detto questo, possiamo scrivere un metodo Main come questo:

static void Main(string[] args) { ConnectorWSS wss = new ConnectorWSS(); wss.UploadDocument("D:\Documenti\test_uploading.txt", "igordamiani/Documenti/test_uploading.txt"); int idFile = wss.GetIDFromFilename("Documenti", string.Empty, "test_uploading.txt"); Dictionary<string, string> values = new Dictionary<string, string>(); values.Add("Note", "Upload di test!"); wss.UpdateDocumentMetadata("Documenti", idFile, values); }

Con poche righe di codice, pubblico un file sulla document library di Sharepoint, ne ottengo l’ID e salvo i metadati costruendo prima un Dictionary<string, string> appositamente.

Technorati Tags:     

Send to Kindle
.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
.NET World

Ottenere l’ID univoco di un file in una document library di Sharepoint

Ho scritto il metodo seguente, che dato un nome di una lista di Sharepoint ed un nome di file pubblicato, restituisce il suo ID univoco. Questo ID può essere utile durante la chiamata ai web-services di Sharepoint. Vediamo insieme come funziona.

1 public void ReadFileID(string listName, string fileName) 2 { 3 string name; 4 Lists l = new Lists(); 5 l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain); 6 7 XmlDocument doc = new XmlDocument(); 8 doc.LoadXml("<Document><Query /><ViewFields /><QueryOptions /></Document>"); 9 XmlNode listQuery = doc.SelectSingleNode("//Query"); 10 XmlNode listViewFields = doc.SelectSingleNode("//ViewFields"); 11 XmlNode listQueryOptions = doc.SelectSingleNode("//QueryOptions"); 12 XmlNode node = l.GetListItems(listName, string.Empty, listQuery, 13 listViewFields, 14 "100", listQueryOptions, null).FirstChild.NextSibling.FirstChild.NextSibling; 15 16 do 17 { 18 if (node.NodeType != XmlNodeType.Whitespace) 19 { 20 if (node.Name.Contains("row")) 21 { 22 name = node.Attributes["ows_FileRef"].Value.Split(';')[1].Replace("#", ""); 23 if (name.Equals(fileName)) 24 { 25 this.CacheFilesID.Add(fileName, node.Attributes["ows_ID"].Value); 26 break; 27 } 28 } 29 } 30 31 node = node.NextSibling; 32 } while (node != null); 33 }

Riga (4) e (5): creo un’istanza della classe wrapper per chiamare il web-services e ne imposto le credenziali per avere l’accesso.

Alla riga (12) avviene la chiamata vera e propria al metodo GetListItems. Esso restituisce un XML che contiene tutti gli elementi pubblicati nella document library, per cui dopo dovremo parsare l’XML per recuperare il file voluto. I parametri nella chiamata non sono pochi. Essi sono rispettivamente: il nome della lista, un eventuali nome della view, l’eventuale query, l’elenco dei campi da vedere, il row limit (messo a 100 in questo caso), eventuali query options ed il Web ID (opzionale).

Questa chiamata restituisce un XmlNode piuttosto lungo e complesso. Il codice non fa altro che saltare tutti i nodi di tipo Whitespace, recupera solo quelli il cui tag è “row”. Quando ne trova uno (riga 22), prendo l’attributo “ows_FileRef” e lo parserizza in modo brutale, splittando sul carattere ‘;’ ed eliminando la presenza del carattere ‘#’. Quando finalmente viene trovato il file voluto, lo inserisce in una cache (Dictionary<string, string>), in modo tale che se viene chiesto in un secondo momento l’ID dello stesso file, posso recuperarlo più velocemente dalla cache.

Technorati Tags:   

Send to Kindle
.NET World

Upload di un file in una document library di WSS: ed i metadati?

Di per sè non è una cosa estremamente complicata. E’ possibile accedere ad una document library di Sharepoint come se fosse un normale path di rete. Detto questo, potete per esempio uploadare un file locale su un server con una banalissima File.Copy – pratica che a me personalmente non piace perchè non è asincrona e soprattutto blocca il thread corrente fino a quando l’operazione non è completata (con successo o meno).

Per l’upload ho preferito usare questo blocco di codice…

public void UploadDocument(string localFilename, string remoteFilename) { FileStream strm = new FileStream(localFilename, FileMode.Open, FileAccess.Read); BinaryReader reader = new BinaryReader(strm); byte[] fileContents = reader.ReadBytes((int)strm.Length); reader.Close(); strm.Close(); string sRemoteFileURL = Settings.Default.ServerWS + "/" + remoteFilename.Trim(); sRemoteFileURL.Replace(@" ", @"%20"); sRemoteFileURL.Replace(@"", @"/"); WebClient client = new WebClient(); client.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain); client.UploadData(sRemoteFileURL, "PUT", fileContents); client.Dispose(); }

…che utilizza la classe WebClient per inviare uno stream di bytes sul server WSS. Il metodo UploadData – che io ho utilizzato – è comunque sincrono, ma ricordo che ci sono le varianti asincrone che seguono il pattern APM. Con questa tecnica, non dovete utilizzare alcun web-service, il che rende il tutto estremamente comodo e semplice da utilizzare.

La parte più complicata, se così vogliamo definirla, è aggiornare eventuali metadati previsti dalla document library nella quale abbiamo copiato il file. Per dirla breve, i metadati sono le colonne aggiuntive che noi abbiamo creato nella document library. Facciamo un piccolo esempio. Supponiamo di aver creato una document library sul nostro server WSS chiamata “Download”: lo scopo è quello di pubblicare su questa lista tutti i files che noi vogliamo far scaricare agli utenti. Oltre alle classiche informazioni di base (Nome del file, Dimensione, Ultima modifica) è possibile creare campi aggiuntivi, così da rendere più fruibile il contenuto della lista (Descrizione, Versione, Requisiti, Tipo di file, etc.). Come è possibile valorizzare questi metadati per un determinato file già uploadato sul server?

Qui le cose si fanno complicate, e bisogna necessariamente fare uso dei web-services di Sharepoint. Per questo tipo di operazione dobbiamo utilizzare il web-service con un url simile a questo:

http://nome_server_WSS/nome_document_library/_vti_bin/lists.asmx

Ecco il metodo che io ho scritto:

1 public void UpdateDocumentMetadata(string listName, string remoteFilename, Dictionary<string, string> values) 2 { 3 string finalFilePath = Settings.Default.ServerWS + "/" + remoteFilename; 4 this.ReadFileID(listName, remoteFilename); 5 string fileID = this.CacheFilesID[remoteFilename]; 6 7 #region Building command using XML 8 StringBuilder strBuilder = new StringBuilder(); 9 strBuilder.AppendLine("<Method ID='1' Cmd='Update'>"); 10 strBuilder.AppendFormat("<Field Name = 'ID'>{0}</Field>", fileID); 11 strBuilder.AppendFormat("<Field Name = 'FileRef'>{0}</Field>", finalFilePath); 12 13 Dictionary<string, string>.Enumerator enumerator = values.GetEnumerator(); 14 enumerator.MoveNext(); 15 16 do 17 { 18 strBuilder.AppendFormat("<Field Name = '{0}'>{1}</Field>", enumerator.Current.Key, enumerator.Current.Value); 19 } while (enumerator.MoveNext()); 20 21 strBuilder.AppendLine("</Method>"); 22 #endregion 23 24 XmlDocument doc = new XmlDocument(); 25 XmlElement elBatch = doc.CreateElement("Batch"); 26 elBatch.InnerXml = strBuilder.ToString(); 27 28 Lists l = new Lists(); 29 l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain); 30 l.UpdateListItems(listName, elBatch); 31 }

Al metodo arriva in input il nome della document library, il nome del file ed un Dictionary<string, string>. Quest’ultimo contiene coppie di key/value per i metadati che vogliamo aggiornare. Alla riga (3) ottengo il path completo del file sul server WSS (esempio: http://nome_server_wss/nome_document_library/nome_file). Alla riga (5) ottengo un ID univoco per il file: per farlo faccio uso di un altro metodo, ReadFileID, che trova il file e riempie una cache, in modo tale che se chiedo in un secondo momento l’ID dello stesso file uso la cache e non più il web-service che adesso voi vedete nascosto nel metodo ReadFileID().

Dalla riga (7) alla riga (26) costruisco un blocco XML che contiene un comando formattato da inviare all’engine di Sharepoint. L’XML contiene l’ID del file e contiene i metadati da aggiornare (ciclo do…while), formati da tanti <Field></Field>, dove l’attributo Name è il nome della colonna nella lista, ed il contenuto del tag è il valore che il metadato corrente deve assumere.

Dalla riga (28) alla riga (30) costruisco un’istanza del web-services ed eseguo una chiamata al metodo UpdateListItems(). Se tutto è andato a buon fine, potete navigare nella document library e controllare il file uploadato: esso avrà i metadati valorizzati così come abbiamo popolato il Dictionary!

Technorati Tags:    

Send to Kindle