Tuesday, January 10, 2012

Non tutte le cancellazioni di Content Type sono uguali

La  cancellazione di un content type non è mai stata una passeggiata. Per cancellare con successo un content type SharePoint internamente effettua una serie di controlli, tra i quali com'è stato deployato il content type (se tramite feature le cose si complicano), che non sia referenziato in siti e liste e naturalmente che non ci siano contenuti ad esso associati.
Nel caso in cui una di queste condizioni non sia soddisfatta viene sollevata un'eccezione che, incrociando le dita, qualche volta è tipizzata (come la famosa SPException: The content type "XYZ" is part of an application feature.)

Tavolta l'object model di SharePoint ci può venire in aiuto. Per ottenere un elenco degli oggetti, siti e liste, che fanno uso del content type che si sta cercando di cancellare, c'è il metodo SPContentTypeUsage.GetUsages().
Per qualche motivo, personalmente ipotizzo sia per ragioni storiche, c'è un ulteriore punto di attenzione molto importante. Mi sto riferendo ad una differenza di implementazione della cancellazione dei content type tra SharePoint Foundation e SharePoint Server. Riporto l'estratto di un articolo su MSDN:

"You cannot delete a site content type if it is being used as the basis for other site or list content types. You must first remove this content type from all lists that use it and delete all child site content types that are based on it.

You cannot delete a content type from a list if that list contains items of that content type. However, Microsoft SharePoint Foundation does not consider items that are in the Recycle Bin. If those items are restored after their content type is deleted from the list, those items are assigned the default content type for that list."

In conclusione quello che suggerisco di fare quando non si riesce a cancellare un content type da object model è verificare approfonditamente i pre-requisiti della cancellazione.
In seconda battuta fare un backup della site collection e poi provare a passare da client side a server side, optare per usare i WebService, la UI, SP Designer (ebbesi si a volta fa i miracoli) e in situazioni estreme e/o per i più temerari fare qualche query sul DB per cercare di individuare il problema considerando sempre che db è fonte di ispirazione ma non di soluzione ai problemi :-) 

Monday, December 19, 2011

WebPart targeting feature con User Profile e custom con IRuntimeFilter2


Nel paradigma delle Intranet 2.0 gioco un ruolo importante la personalizzazione dei contenuti. Sintetizzando il concetto possiamo dire che gli utenti devono essere in grado di navigare una intranet ottenendo contenuti personalizzati. Quali sono i criteri di personalizzazione? Sicuramente un ricco profilo utente può essere un'ottima fonte di informazioni per definire un audience, ma non è l'unica fonte dati. L'appartenenza a gruppi potrebbe essere di interesse per individuare classi di profilo. Talvolta sono necessario delle logiche personalizzate che si basano su dominio, nome utente o informazioni contenuti in altri sistemi (ad esempio sistema di HR).

Calando il requisito su SharePoint troviamo una funzionalità che fa il caso; è il targeting e può essere applicato ad interi contenuti (item in generale) o parti di un contenuto (webpart). Il targeting viene presentato come un campo con il picker che ne permette la selezione di audience, distribution list e sharepoint group. 

Con l'amico Carmelo abbiamo appronfondito gli internals. La configurazione di SharePoint richiede che per usare la funzionalità dei targeting sia necessario configurare la User Profile Service Application e associarla alla web application tramite il proxy; senza la USPA associata alla web application, non viene visualizzata la proprietà della webpart Target Audience all'interno della ToolPart.



Il sistema del targeting è implementato a basso livello e questo ne per permette l'applicazione sulle webpart senza richiedere specifici sviluppi.
Queste caratteristiche fanno si che il targeting sia disponibilie sono sulla versione Server e non quella  Foundation. 

Qui è nata la mia curiosità e l'approfondimento di questo post. Domande tipo "è possibile fare uso del targeting anche senza UPSA?" o "se le formazioni delle audience sono contenuti sui gruppi SharePoint perchè dobbiamo necessariamente fare uso della USPA?" o "sono ammesse logiche custom per l'assegnazione della audiences?"

Il principale indagato era un componente che viene istanziato in tutte le webpart, la cui configurazione è salvata sul web.config nella chiave SharePoint/RuntimeFilter. Sto parlando di questa chiave

La classe Microsoft.Office.Server.Audience.AudienceManager implementa le interfacce IRuntimeFilter (ormai obsoleta) e IRuntimeFilter2 usata dal WebPartManager per valutare se il sistema di filtro delle webpart debba essere valutato e utilizzato, e ne influenza la visualizzazione all’interno della Toolpart. Ho verificato che commentando questa chiave le webparts non visualizzando più il campo Target Audiences.

Facendo qualche ricerca ho trovato che componente era già presente su di Microsoft.SharePoint.Portal, Version=11.0.0.0 (naturalmente al tempo non c'erano ancora le service application); il sistema ha quindi un punto di estendibilità e permette di implementare custom runtime filter per andare ad gestire i filtri sulle webpart. Ne parla approfonditamente il libro SharePoint 2010 Web Part in Action di Wictor Wilén (SharePoint MVP e MCM) dedicando appunto un capitolo all’implementazione di un custom filter

"The runtime filter in SharePoint is a specific class derived from the IRuntimeFilter2 interface. This class is registered in the web.config file and is called for every Web Part when rendering a page. A specific method in the class tells SharePoint whether it should be shown to the user. In this section you’ll create a custom runtime filter that can be used to target the Web Part using the site collection groups. This will give you the option to target Web Parts to specific groups even in SharePoint Foundation."

Thursday, December 15, 2011

Ottenere la versione di SharePoint


Ottenere la versione della build di SharePoint 2010 è un operazione estremamente semplice, ma ... ci sono dei ma.

Il metodo migliore per ottenere la versione è quello di aprire la Central Admin e nella sezione System Settings accendere alla voce Manage servers in this farm (http://site/_admin/FarmServers.aspx).


Per avere delle informazioni di dettaglio su tutti i componenti installati (es. language pack) si può andare su Upgrade and Migration e selezionalare Check product and path installation status (http://server/_admin/PatchStatus.aspx)



In entrambe i casi è comunque necessario fare accesso alla Central Admin. Ci sono alternative?

Se abbiamo accesso al SQL Server che ospita il database della Central Admin e si ha a disposizione SQL Management Studio, questo script TSQL ci restitusce la build number.
SELECT Version, UserName
FROM Versions
WHERE VersionId = '00000000-0000-0000-0000-000000000000'
ORDER BY Id DESC

Se possiamo fare girare del codice su server SharePoint si può creare una console application che estrae le stesse infomazioni.
using (SPSite startSite = new SPSite("")) {
   SPFarm farm = startSite.WebApplication.Farm;
   SPWebService service = farm.Services.GetValue("");  
   foreach (SPWebApplication webApplication in service.WebApplications) {
      foreach (SPSite site in webApplication.Sites)   {
         Console.WriteLine(string.Format("{0} - {1}", site.Url, site.ContentDatabase.Name)); 
      }
   }
}

Naturalmente questi metodi devono essere eseguiti con un utente che abbia i diritti appropriati. Se non avessimo questi diritti? Se fossimo abilitati ad accedere ad una site collection con una security più limitata? Per farla ancora più difficile: da un sito di publishing pubblicato su internet e acceduto in modalità anonima possiamo identificare la build installata?
La risposta è sì, ma ... non è detto che il dato ottenuto sia "sempre" affidabile.

Per ottenere la versione si deve analizzare il contenuto delle HttpResponse generate da SharePoint  e tra gli header troveremo uno dal nome MicrosoftSharePointTeamServices. Questo header è configurato su IIS da SharePoint 2010 e mantenuto aggiornato dai vari  aggiornamenti di SP e CU.



Via Javascript possiamo così scrivere alcune righe di codice per risalire dalla build.
var xmlHttp = new XMLHttpRequest();
var url = "http://yoursite"; 
xmlHttp.open('HEAD', url, false);
xmlHttp.send();
var SPVersion = xmlHttp.getResponseHeader("MicrosoftSharePointTeamServices");

NOTE: talvolta gli IT Admin considerano che l'esposizione di questo tipo di informazioni possa in qualche modo 'ledere' la sicurezza della farm. Il ragionamento è "se chiunque è in grado di ottenere informazioni sul livello di Patch, la stessa persona potrebbe attaccare la piattaforma sfruttando le vunerabilità conosciute". Di fatto però la maggior parte dei siti internet ospitati su SharePoint espongono questa informazione ... provare per credere!


UPDATE 15/1: ovviamente anche via Powershell con l'addin di SharePoint 2010 otteniamo la build tramite (Get-SPFarm).BuildVersion

Sunday, November 6, 2011

PowerShell ISE e SharePoint

Lavorando con SharePoint a tutti i livelli capiterà, a chi prima ed a che poi, di scrivere dei PowerShell con fare configurazioni, procedure di deploy, setup di servizi, addirittura il setup di tutta la farm e in generale gran parte, se non tutte, le attività amministrative. Naturalmente con il tempo la frequenza di utilizzo di PowerShell aumenta sempre più dapprima si passerà a realizzare e magari scopiazzare semplici script e piano piano si passerà a cose ben più complesse. Come dico sempre ai ragazzi che si avvicinano a SharePoint è PowerShell will be your best friend :)

SharePoint mette a disposizione direttamente dall’elenco della applicazioni SharePoint 2010 Management Shell. Un prompt dei comandi PowerShell nel quale è pre caricato lo snapin Microsoft.SharePoint.PowerShell.dll. Con un click si può iniziare a scrivere snippet powershell per SharePoint.

Sfruttando PowerShell ISE, un tool incluso nel sistema operativo, si invece ha un vero ambiente di debugging degli script powershell.
 
image

Naturalmente PowerShell ISE non carica automaticamente l’assembly con le estensioni SharePoint per PowerShell. E’ quindi necessario inserire come prima riga dello script il comando
Add-PSSnapin Microsoft.SharePoint.Powershell
e farlo eseguire una volta sola perchè le successive avranno lo snippet precaricato (spesso infatti viene commentato).

Ovviamento l’approccio è migliorabile. E’ sufficiente scrivere qualche riga in più e con uno script più sofisticato controlliamo se lo snapin è già stato caricato. Se non lo è si fa il caricamento, diversamente prosegue.
if ((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null) {    Add-PSSnapin Microsoft.SharePoint.PowerShell; }

Ammetto però che dover scrivere, meglio copiare, queste righe tende ad essere una perdita di tempo e ci espone ogni volta ad probabili errori di battitura. Per semplificare maggiormente l'approccio ci viene in aiuto la funzionalità PowerShell Profiles. Un sistema che quando configurato esegue in fase di caricamento un proprio script ed è in questo script che noi andremo ad innestare il caricamento dello snapin. Come si fa?
E' necessario creare uno profile script, io uso questa tipogia %UserProfile%\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1, aprire il ps1 e inserire queste righe di codice che vanno a configurare il riutilizzo dello thread ad ogni esecuzione di script e caricano l'assembly con le estensioni PowerShell per SharePoint. 
$ver = $host | select version
if ($ver.Version.Major -gt 1) {$host.Runspace.ThreadOptions = "ReuseThread"}
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) {
   Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}


D’ora in poi ad ogni apertura di PowerShell ISE verrà caricato lo snapin di SharePoint e anche voi direte come me: “questa si che è vità!!!”

Sunday, October 23, 2011

Export e Import TermSet

Dal momento in cui il backup e restore delle site collection non includono le informazioni contenuti nella Service Application Managed Metadata è facile capire che se una site collection fa uso di colonne di tipo Managed Metadata queste saranno si backuppate (odio questo termine ma lo uso per semplicità) ma non nella loro interezza. Per dirla un pò meglio sarà backuppato solo il valore del identificativo, un guid, del term e una lista nascosta che contiene il nome dei Term utilizzati.

In questi casi è importanti che ci sia allineamento tra il backup della site collection e del Managed Metadata per i TermSet e Terms in essa contenuti.
Ad esempio se a seguito di un back di una site collection sono stati eliminati dei Term e questi erano stati usati nei contenuti sarà necessario ‘ripristinare’ sia la site collection che il managed metadata. Lo stesso discorso va applicato per spostare una site collection da una farm ad un’altra.

Facendo un export del managed metadata dalla farm source e import su quella target verrà ristabilita la normale operatività.
Export
Seguire passo passo la procedura qui descritta per esportare i TermSet:
  1. Aprire il command Powershell di SharePoint 2010 in modalità Amministrativa
  2. Per ottenere il GUID della Managed Metadata SA (MMSA) eseguire
    Get-SPServiceApplication
  3. Per ottenere il GUID della Managed Metadata SA (MMSA) eseguire
    Get-SPServiceApplicationProxy
  4. Modificare il seguente script inserendo il path e nome del file di export dei TermSet e i GUID ottenuti nei passi 2 e 3 rispettivamente sulle variabili $mmsApp e $mmsProxy
    $mmsApp = "1de49354-364c-4b00-b938-993eee8bf8a7";$mmsProxy = "8caa7f5f-d68b-40f3-8243-e8ae01573ec8";Export-SPMetadataWebServicePartitionData -Identity $mmsApp -ServiceProxy $mmsProxy -Path W:\MMSexportfile.bak;
Import
Seguire passo passo la procedura qui descritta per importare i TermSet:
  1. Copiare il file di export dei TermSet sulla farm target
  2. Per ottenere il GUID della Managed Metadata SA (MMSA) eseguire
    Get-SPServiceApplication
  3. Per ottenere il GUID della Managed Metadata SA (MMSA) eseguire
    Get-SPServiceApplicationProxy
  4. Modificare il seguente script inserendo il path e nome del file di export dei TermSet e i GUID ottenuti nei passi 2 e 3 rispettivamente sulle variabili $mmsApp e $mmsProxy
    $mmsApp = "1de49354-364c-4b00-b938-993eee8bf8a7";$mmsProxy = "8caa7f5f-d68b-40f3-8243-e8ae01573ec8";Import-SPMetadataWebServicePartitionData -Identity $mmsApp -ServiceProxy $mmsproxy -path W:\MMSexportfile.bak -OverwriteExisting;
Troubleshooting
Come approcciare i problemi comuni:
  • Eseguire powershell cmd in Administrative mode
  • Se il comando di export lanciato via powershell restituisce un errore di Access denied
clip_image002
L’utente dell’app pool del servizio MMSA non ha accesso in scrittura al path specificato. Da IIS Manager ottenere l’identity dell’app pool della MMSA e dare full control sul path specificato
  • Se durante l’operazione di Restore dei “Managed Metadata” ottenete il messaggio di errore
You do not have permission to use the bulk load statement

Aggiungere su Sql Server nel gruppo “bulkadmin” l’utenza dell’application pool. Ulteriori info qui
  • Se durante l’operazione di Restore dei “Managed Metadata” ottenete il messaggio di errore
Import-SPMetadataWebServicePartitionData : Cannot bulk load because the file "C:\99f6833d2bac4c53af26b816afca1d55\ECMGroup.dat" could not be opened.

To work around, instead of keeping file on Application Server, I kept it on SQL Server box and used the network path to the file in command. You have to give read write access to this share as PowerShell creates temporary files while importing TermStore. After this the command worked as expected and we were able to import TermStore succesfully. More info here

Monday, September 26, 2011

Enhanced Social Feature (ESF) Project – ActivityAggregator

Activity feed 101
Avete presente l’elenco delle attività recenti di Facebook ? Una cosa abbastanza simile è stata implementata su SharePoint 2010. Si chiama Activity Feed e lo si può vedere sul My Site nell’area My Newsfeed (è un servizio di SharePoint Server che naturalmente deve essere esplititamente attivato e configurato). L’activity feed di SharePoint non ha tutte le features di Facebook ma in un ambiente di collaboration/enterprise social forse non sono necessarie, ma la mancanza di qualcuna di esse si fa sentire. Infatti la cosa che balza subito all’occhio dopo poche settimane di utilizzo e l’aggiunta di un numero elevati di colleghi, è la quantità di informazioni che presenti sul feed. Si rischia di perdere aggiornamenti e a differenza di Facebook l’activity feed di SharePoint non permette di “navigare nel tempo”.

Enhance activity feed 
A fonte dell’alto numero di feed generati dalle attività dei colleghi è nessario uno strumento per aggregare le activity e organizzarle in modo più compatto. Ad esempio ogni volta che un collega aggiunge altre persone tra i suoi colleghi viene scritto un feed per notificare dell’avvenuta aggiunta. Se nel corso di un giorno vengono aggiunte a più riprese 10 persone, nel mio feed troverò 10 activity. Stessa cosa vale per gli aggiornamenti del profilo utente, per i cambi di stato, ecc… Tutte queste informazioni ci servono veramente? Non possono essere sintetizzate?
Da questi ragionamenti è nato Activity Aggregator, un componente che si basa sulle activity originali tracciate da SharePoint e le aggrega tramite algoritmi personalizzabili. E’ sviluppato con un’architettura open, o meglio a provider, nella quale è sufficiente implementarne di propri, registarli e il gioco è fatto! :)
Vai su http://esf.codeplex.com per maggiori informazioni e per scaricare il codice aggiornato. La versione attuale è una beta ed utilizzabile unicamente come preview della versione finale.

Implementazione 
Sono quatto i componenti chiave del ActivityAggregator:
  1. QueryActivity che si occupa di interrogare SharePoint per ottenere il feed della azioni compiute del mio network
  2. ActivityAggregatorProvider usato come pipeline per le trasformazioni del feed. Sviluppando provider propri e configurandoli sul web.config si agisce sulle singole activity del feed. E’ data massima libertà alle trasformazioni: si possono nascondere e trasformare le activity esistenti senza che queste impattino sulle quelle di SharePoint (non viene persistito nulla sul SocialDb). Si tratta quindi di operazioni di trasformazioni effettuate in memoria. Per migliore le performance potrebbe diventare necessario l’inserimento di cache (funzionalità al momento non presente).
  3. ActivityFormatter che ha come scopo quello di modificare la formattazione delle activity trasformate. Per formattazione si intendo ciò che viene visualizzato nell’activity feed (es. testo, immagini, link, ecc…). Tramite l’utilizzo di un file di risorse tutte le formattazioni possono essere gestite in modalità multilingua.
  4. La webpart ExtendedActivityAggragatorWebPart è quella che ci occupa di visualizzare le social activity, come avviene già per  i My NewsFeed con la webpart OOB di SP, a valle della trasformazione e formattazione.
Le feature ActivityAggregatorFeature installa la webpart sulla WebPart Gallery e in fase di attivazione si occupa di registrare i type mapping degli oggetti di query che vengono gestiti tramite il pattern Service Locator (quella fornito da Microsoft Pattern & Practice Guidance for SharePoint 2010).


Activity Aggregator Providers
In questa build sono inclusi alcuni provider di trasformazione delle social activity:
  • ProfileChangePropertyActivityAggregatorProvider che si occupa di visualizzare una sola activity per i change di profilo di tutti gli utenti del mio network nell’arco di un giorno.
  • LimitChangesUserStatusActivityAggregatorProvider visualizza un numero ridotto di cambi di status per ogni utente. Il numero è configurabile tramite web.config
  • CollegueAddictionActivityAggregatorProvider che aggrega in un unica activity tutte le aggiunte di colleghi avvenute nell’arco di un giorno

Risultato finale 
Ecco un esempio di activity feed di OOB di SharePoint e del Activity Aggregator di ESF for SharePoint 2010

Activity feed di SharePoint 2010
image

Activity Aggregator di ESF for SharePoint 2010
image

Thursday, September 8, 2011

Upgrade di SharePoint dalla August CU

Finalmente quello che volevamo sentir dire da mesi è stato annunciato.
Di cosa parlo? Non certo del rilascio programmato della CU di Agosto. Si certo interessante ma non stepitoso.
Parlo della nuova modalità per l'aggioramento delle CU di SharePoint che Microsoft ha introdotto.

Fino ad poco fa per installare le CU di SharePoint Server, Microsoft aveva dato indicazione di scaricare (il che significa un bel pò di tempo data la dimensione dei pacchetti) e installare sia SharePoint Foundation che SharePoint Server. Più volte ho discusso con colleghi di Avanade e Microsoft se era proprio necessario compiere le due installazioni. Il risultato di queste discussioni portava alla conclusione cha procedura supportata è quella e che comuque il pacchetto di upgrade di SharePoint Server contiene (quasi) sempre tutti i bits.

Ora la "svolta". Sulle pagine ufficiali degli Update di SharePoint fanno sapere che è stato cambiato approccio e che in soldoni c'è un pacchetto di aggiornamento cumulativo per ogni versione di SharePoint.
Questo appoccio semplificato e indicato da Microsoft come Best Practice è finalmente realtà.