giovedì 25 giugno 2009

Feed RSS con SharePoint - Errata Corrige

In un precedente articolo (Feed RSS con SharePoint - 2/2) ho scritto il seguente codice per impostare una data all'interno del feed RSS:

xtw.WriteElementString(”pubDate”, pages.Created.ToString(”R”));

Questo però genera un problema con i reader (per esempio Outlook). Il metodo ToString della classe DataTime riporta in stringa la data letta da Sharepoint nel formato GMT, ma non aggiorna la data rispetto al meridiano di Greenwich! I reader invece interpretano la data come riferita al meridiano e la correggono in base al fuso orario del paese in cui si trovano, quindi per l'italia in regime di ora legale sommano 2 ore. Capita così di avere item che riportano un orario di insermento superiore all'orario attuale. Per sistemare il problema, bisogna usare l'istruzione seguente:

xtw.WriteElementString(”pubDate”, pages.Created.ToUniversalTime.ToString(”R”));

L'istruzione ToUniversalTime invece riconverte la data rispetto al meridiano di Greenwich.

martedì 23 giugno 2009

Alternative Rendering Framework (ARF)

Già in precedenza ho accennato al framework ARF, in quanto mi è venuto comodo per rendere accessibili alcuni componenti del WCM di MOSS. In questo periodo ho ripreso in mano il framework, anche perchè ci sono state della aggiunte, e vorrei provare a spiegarne l'utilizzo. Il problema è che il framework è poco documentato e non sempre intuitivo; volevo quindi lanciare una proposta, ovvero chiunque ha usato il framework o ha materiale in merito mi può contattare o postare un commento per aiutarmi a scrive una serie di articoli in italiano che descrivano al meglio alcuni aspetti di questo strumento.

A breve ho intenzione di parlarvi dei controlli SiteQuery e ListQuery di ARF che ho usato con WSS e che mimano un pochino la funzionalità delle Content by Query Web Part, XML e XSL compresi.

Rinnovo l'invito a farsi avanti a tutti coloro che avessero informazioni su ARF.

Intanto vi segnalo un embrione di sito documentativo sull'argomento: http://arf.thekid.me/Pages/default.aspx

lunedì 8 giugno 2009

Finalmente online

Sono molto contento di annunciare che ha visto finalmente la luce il progetto che mi ha impegnato per tanti mesi, tutto fatto con SharePoint e che mi ha fornito molti spunti per gli articoli che ho pubblicato.

Andando su www.atm-mi.it potrete vedere il risultato di tanto lavoro.

———————————————————————–
Parlano di noi:
Da oggi i trasporti di Milano viaggiano su SharePoint



venerdì 29 maggio 2009

CAML Query e Stato di un Item

Come sicuramente tutti sanno per testare lo stato di moderazione (_ModerationStatus) di un item in SharePoint con una query CAML si fa in questo modo:

<Query>
<Where>
<Eq>
<FieldRef Name=”_ModerationStatus” />
<Value Type=”ModStat”>Approved</Value>
</Eq>
</Where>
<Query>

Si nota subito che non  viene usato un codice (che sarebbe multilingua) ma un valore letterale, quindi se si installa SharePoint in Italiano questa query CAML non funzionerà. I valori possibili forniti da SDK sono:

Member name

Description

Approved The last major version of the item is
displayed in the public views of the list or document
library.
Denied The last major version of the item is not
displayed in the public views of the list or document
library.
Draft The item minor version is being edited and is
not ready for approval.
Pending The decision about displaying the item in
public views of the list or document library is pending.
Scheduled The decision about displaying the item in
public views of list or document library is pending and will be
processed by a timer service.

La traduzione in italiano degli stati dovrebbe essere:

Approvato
Negato
Bozza
In Sospeso
Pianificato

Alla prossima!



mercoledì 27 maggio 2009

WCM Variation & PageLayout

Per un progetto che sto seguendo, mi è capitato di dover affrontare questo problema:

“Avendo attivato le variation in un sito di publishing in cui sono stati crati dei custom web provisioning, ovvero delle classi che si occupano di fare alcune operazioni in fase di creazione di un sito, registrati in una custom site definition, mi è capitato che le home page dei siti ri-creati dal sistema di variation perdessero tutti i page layout associati, matenendo solo quello definito di default. Andando a controllare nella lista Pages le proprietà della default page si vedeva chiaramente che in presenza di contenuti questi venivano renderizzati in modo non corretto perchè mancava il giusto page layout.”

Fortunatamente esiste sempre un pio uomo sulla terra che affronta per primo questi problemi e in questo caso è stato Garry Lapointe che ci mette a disposizione una fantastica collezioni di custom extention per stsadm, tra cui esiste il comando: gl-fixpublishingpagespagelayouturl che permette di riassociare un page layout ad una pagina, ma non solo…

Con questo fantastico comando ho potuto risolvere il mio problema.



giovedì 14 maggio 2009

Scrivere in un SPFolder

Recentemente ho consigliato ad un cliente di utilizzare la possibilità di SharePoint di creare e scrivere in folder invece che in liste, visto che aveva la necessità di memorizzare solo dei dati (immagini) volanti e non permanenti, che dopo poco tempo dovevano essere rimossi. Il folder in questione è stato creato nella site collection per mezzo di una semplice feature che caricava un file di testo nel foder stesso consentendone la creazione. In socondo luogo abbiamo scritto il codice per accedere al foleder ed aggiornarne il contenuto.

Il codice in questione è il seguente:

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb elevatedWeb = elevatedSite.OpenWeb(SPContext.Current.Web.ID))
{
//creo un’istanza di SPfolder che mi aggancia alla cartella creata all’attivazione della FEATURE
SPFolder <NomeOggettoSPFolder> = elevatedSite.RootWeb.Folders["<NomeDellaFolder>"];
elevatedWeb.AllowUnsafeUpdates = true;
//aggiungo il file alla cartella temporaneamente
<NomeOggettoSPFolder>.Files.Add(FileUpload1.FileName, FileUpload1.FileBytes, true);
<NomeOggettoSPFolder>.Update();
elevatedWeb.AllowUnsafeUpdates = false;
}
}

});

E’ importante notare che per aggirare i problemi di sicurezza si è scelti di elevare i diritti di esecuzione e per farlo correttamente si è dovuto creare una Site Collection clone dell’originale e un Web Site clone dell’originale in modo che il contesto risultasse con gli opportuni privilegi. Il resto del codice si commenta da sè, l’unica cosa che posso far notare è l’utilizzo di un controllo .Net per l’upload del file, che nel nostro caso si chiama FileUpload1.

Alla prossima.



venerdì 24 aprile 2009

Accedere alle WebPart di una pagina

Se si ha la necessità di accedere alla form di gestione delle webpart inserite in una pagina è sufficiente porre in query string il seguente parametro “contents=1″.

quindi ad esempio: http://nome_server/Pages/default.aspx?contents=1



martedì 24 marzo 2009

Identificatore univoco per i ListItem

Dovendo recuperare un item di una lista dopo averne fatto un content deploy un mio collega e io ci siamo domandati se ci fosse una proprietà degli item che rimaneva immutata tra sorgente e destinazione: l’abbiamo trovata usando SharePoint Manager. La proprietà in questione è UniqueId; MSDN recita “Gets the GUID that uniquely identifies the item for the internal database” e nulla più. UniqueId è una proprietà di SPListItem. Nel nostro caso i prima battuta usavamo SPContext.Current.Item["GUID"] pensando di aver identificato un valore univoco, invece ci siamo accorti che questo valore con il content deploy variava. Invece utilizzando SPContext.Current.ListItem.UniqueId abbiamo risolto il problema.

Altra cosa interessante è la possibilità di usare questo valore per recuparare un publishing page da una lista Pages tramite Content Query Web Part, infatti con una semplice query CAML del tipo:

<span lang="EN-US"><Where></span><span lang="EN-US">
<Eq>
<FieldRef Name='UniqueId' />
<Value Type='Text'></span><span lang="EN-US">{9C5324A9-BD5D-411C-9F78-7F494BF87985}</span><span lang="EN-US"></Value>
</span> </Eq>
</Where>

è possibile raggiungere il risultato. Sempre usando una Content Query Web Part, estesa da noi in modo da fare override delle proprietà come OvverideQuery, ho scoperto, che istruendo la web part ad estrarre anche la proprietà UniqueId e usando il sitema di debug di Heather Salomon, la proprietà si presenta come segue:

<span lang="EN-US">V:<strong>1;#{9C5324A9-BD5D-411C-9F78-</strong><strong>7F494BF87985}</strong></span>

con lo stesso formalismo di un campo di lookup, dove il numero che precede ;# corrisponde all’ID dell’item nella lista, mentre il codice tra parentesi graffe è l’UniqueId.

Infine segnalo un sistema per esporre lo UniqueId di una pagina di un publishing site in un page layout (comodo anche per altre proprietà del ListItem)

<span lang="EN-US"><SharePointWebControls:ListItemProperty<br />runat="server" id="ListItemProperty1" Property="UniqueId"<br />InDesign="True" /></span>

Alla prossima!



giovedì 19 febbraio 2009

SharePoint Administrators Summit 2009

Al summit a cui ho partecipato Martedì 17 Febbraio i relatori hanno menzionato una serie di tools utili per sharepoint che vi elenco di seguito (almeno quelli che sono riuscito ad annotarmi):

  1. SUSHI
  2. SharePoint Capacity Planning Tool
  3. SharePoint Cross-site Configurator
  4. SharePoint Migration Framework
  5. Estensioni per STSADM di Gary Lapoint


venerdì 13 febbraio 2009

XSLT Point 0.1

Dall’articolo sulle CQWP è nata l’idea di aprire un progetto su CodePlex chiamato XSLT Point che mette a disposizione di tutti qualche utile (spero) XSL per esplorare le Content Query WebPart.

domenica 8 febbraio 2009

Feed RSS con SharePoint - 2/2

Ritorno sull’argomento Feed RSS per segnalare come implementare una pagina custom che generi dei feed RSS versione 2.0 in ambito di siti di publishing; insomma per articoli scritti con il WCM di SharePoint.Per cominciare ho scelto di generare un feed usando come sorgente la lista Pagine/Pages di un sito web il cui GUID mi viene passato in query string. In aggiunta, visto che in una lista Pagine ci possono essere item di tipo diverso ho deciso di farmi passare anche il content type degli item da estrarre. Detto questo per rispettare le specifiche degli RSS 2.0 e per sfruttare SharePoint recupero alcune proprietà memorizzate a livello di site collection, utili per impostare le informazioini che descrivono il canale (channel):

SPSite site = SPContext.Current.Site;
SPWeb root = site.RootWeb;
rss_Copyright = root.AllProperties["vti_rss_Copyright"].ToString();
rss_ManagingEditor = root.AllProperties["vti_rss_ManagingEditor"].ToString();
// Time to Live in minuti
rss_TimeToLive = root.AllProperties["vti_rss_TimeToLive"].ToString();
rss_WebMaster = root.AllProperties["vti_rss_WebMaster"].ToString();

Ora posso cominciare a scrivere il codice per generare il canale:

PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
SPList pages = web.Lists[PublishingWeb.GetPagesListName(web)];

PublishingPage page = null;

// delcare and instantiate XMLTextWriter object
MemoryStream stream = new MemoryStream();
XmlTextWriter xtw = new XmlTextWriter(stream, Encoding.UTF8);

// write out the XML declaration and version 1.0 info
xtw.WriteStartDocument();

// write out the rss xml element “rss” (required)
xtw.WriteStartElement(”rss”);
xtw.WriteAttributeString(”version”, “2.0″);

// write out “channel” element (required)
xtw.WriteStartElement(”channel”);

// write out title, link, and description based on the feed being requested,
// all three elements are required
xtw.WriteElementString(”title”, “RSS Feed”);
xtw.WriteElementString(”link”, web.Url);
xtw.WriteElementString(”description”, web.Description);
// attributi opzionali
xtw.WriteElementString(”generator”, generator);
xtw.WriteElementString(”copyright”, rss_Copyright);
xtw.WriteElementString(”managingEditor”, rss_ManagingEditor);
xtw.WriteElementString(”webMaster”, rss_WebMaster);
xtw.WriteElementString(”ttl”, rss_TimeToLive);
xtw.WriteElementString(”language”, pWeb.Label.Language);
xtw.WriteElementString(”docs”, docs);
xtw.WriteElementString(”pubDate”, pages.Created.ToString(”R”,
CultureInfo.CreateSpecificCulture(”en-US”)));
xtw.WriteElementString(”lastBuildDate”, pages.LastItemModifiedDate.ToString(”R”,
CultureInfo.CreateSpecificCulture(”en-US”)));

L’ultimo passo è generare un elemento ITEM per ogni item della lista.

// Recupero ITEM tramite query CAML
SPListItemCollection items = pages.Items;

foreach (SPListItem item in items)
{
if (PublishingPage.IsPublishingPage(item) && ValidItem(item,contentTypes))
{
page = PublishingPage.GetPublishingPage(item);

if (page.LastModifiedDate <= DateTime.Now.AddDays(-MaxDays))
{
continue;
}

xtw.WriteStartElement(”item”);
xtw.WriteElementString(”title”, page.Title);
xtw.WriteElementString(”link”, page.Uri.ToString());
xtw.WriteStartElement(”description”);
xtw.WriteCData(item.Properties["PublishingPageContent"].ToString());
xtw.WriteEndElement();
xtw.WriteElementString(”pubDate”, page.CreatedDate.ToString(”R”,
CultureInfo.CreateSpecificCulture(”en-US”)));
xtw.WriteStartElement(”guid”, page.Title);
xtw.WriteAttributeString(”isPermaLink”, “true”);
xtw.WriteString(page.Uri.ToString());
xtw.WriteEndElement();
xtw.WriteEndElement();
}
}

// Close all tags
xtw.WriteEndElement();
xtw.WriteEndElement();
xtw.WriteEndDocument();

xtw.Flush();

string resultXml = null;
using (stream)
{
stream.Position = 0;
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
resultXml = reader.ReadToEnd();
}
}

xtw.Close();

return resultXml;

La funzione ValidItem() si occupa di verificare che l’item sia del tipo contenuto voluto. Seguendo questo codice e con qualche linea in più, per esempio per gestire un minimo di cache, è possibile creare il proprio generatore di Feed RSS.



sabato 7 febbraio 2009

Vivisezioniamo il foglio di stile XSLT ContentQueryMain - Prima Parte

In un sabato decisamente umido, per non dire completamente fradicio, vista l’acqua che sta venendo, ho trovato un po’ di tempo per approfondire la conoscenza con le Content Query Web Part (CQWP) e più precisamente con i sui stili XSL. Volevo prendere dimestichezza con gli stili di default per poterne realizzare di miei in modo da personalizzare i risultati della webart nei mie progetti. Il compito è stato facilitato dalla passione che ho nei confronti del linguaggio XSLT, che ho appreso qualche anno fa lavorando per il portale de ‘il Sole 24 Ore’, il cui rendering era completamente basato sulle trasformazioni dei contenuti in XML con XSLT.

Per cominciare mi sono letto un articolo di Microsoft, presente anche nello SDK di MOSS, “How to: Customize XSL for the Content Query Web Part“, che mi ha presentato i tre fogli di stile ContentQueryMain, ItemStyle.xsl e Header.xsl. Descrivendo i template di ItemStyle l’articolo elencava le funzioni usate per facilitare l’estrazione dei dati dal risultato. A questo punto della lettura cresceva sempre di più dentro di me la voglia di capire quale XML produce una CQWP e come funzionano queste funzioni, anche perchè conoscerle può aiutare a semplificare il lavoro e ottenere risultati solidi e in linea con la filosofia del prodotto.

Ecco un elenco delle funzioni OOTB contenute nell’XSL ContentQueryMain:

  1. OuterTemplate.GetSafeLink
  2. OuterTemplate.GetSafeStaticUrl
  3. OuterTemplate.GetColumnDataForUnescapedOutput
  4. OuterTemplate.GetTitle
  5. OuterTemplate.FormatColumnIntoUrl
  6. OuterTemplate.FormatValueIntoUrl
  7. OuterTemplate.Replace
  8. OuterTemplate.GetPageNameFromUrl
  9. OuterTemplate.GetPageNameFromUrlRecursive
  10. OuterTemplate.GetGroupName
  11. OuterTemplate.CallPresenceStatusIconTemplate

Queste “funzioni” che in realtà sono dei template xsl aiutano ad estrarre le informazioni in modo corretto dall’elemento xml passato. Ritorna a questo punto la prima delle questioni: recuperare il risultato della query, insomma vedere l’xml prodotto dalla CQWP. Girovangando su internet ho trovato un po’ di spunti. Heather Solomon spiega come vedere le proprietà degli item estratti (ovvero gli attributi dell’elemento row):

“aggiungere nel file ContentQueryMain un proprio template del tipo:”

<xsl:template name=”MyCustomStyle” match=”Row[@Style='MyCustomStyle']” mode=”itemstyle”>
<xsl:for-each select=”@*”>
P:<xsl:value-of select=”name()” />
</xsl:for-each>

</xsl:template>

Ma questo non mi bastava, volevo avere sottomano un file XML. A questo punto ho deciso di creare un mio foglio di stile partendo dal ContentQueryMain originale e usare la tecnica dell’identity, così ho prodotto questo codice (IdentityContentQueryMain.xsl):

<xsl:stylesheet version=”1.0″ exclude-result-prefixes=”x xsl cmswrt cbq” xmlns:x=”http://www.w3.org/2001/XMLSchema” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:cmswrt=”http://schemas.microsoft.com/WebPart/v3/Publishing/runtime” xmlns:cbq=”urn:schemas-microsoft-com:ContentByQueryWebPart”>
<xsl:output method=”xml” version=”1.0″ encoding=”UTF-8″ indent=”yes”/>
<xsl:param name=”cbq_isgrouping”/>
<xsl:param name=”cbq_columnwidth”/>
<xsl:param name=”Group”/>
<xsl:param name=”GroupType”/>
<xsl:param name=”cbq_iseditmode”/>
<xsl:param name=”cbq_viewemptytext”/>
<xsl:param name=”SiteId”/>
<xsl:param name=”WebUrl”/>
<xsl:param name=”PageId”/>
<xsl:param name=”WebPartId”/>
<xsl:param name=”FeedPageUrl”/>
<xsl:param name=”FeedEnabled”/>
<xsl:param name=”SiteUrl”/>
<xsl:param name=”BlankTitle”/>
<xsl:param name=”BlankGroup”/>
<xsl:param name=”UseCopyUtil”/>
<xsl:param name=”DataColumnTypes”/>
<xsl:param name=”ClientId”/>
<xsl:template match=”/”>
<xml-cqwp>
<params>
<xsl:element name=”cbq_isgrouping”>
<xsl:value-of select=”$cbq_isgrouping”/>
</xsl:element>
<xsl:element name=”cbq_columnwidth”>
<xsl:value-of select=”$cbq_columnwidth”/>
</xsl:element>
<xsl:element name=”Group”>
<xsl:value-of select=”$Group”/>
</xsl:element>
<xsl:element name=”GroupType”>
<xsl:value-of select=”$GroupType”/>
</xsl:element>
<xsl:element name=”cbq_iseditmode”>
<xsl:value-of select=”$cbq_iseditmode”/>
</xsl:element>
<xsl:element name=”cbq_viewemptytext”>
<xsl:value-of select=”$cbq_viewemptytext”/>
</xsl:element>
<xsl:element name=”SiteId”>
<xsl:value-of select=”$SiteId”/>
</xsl:element>
<xsl:element name=”WebUrl”>
<xsl:value-of select=”$WebUrl”/>
</xsl:element>
<xsl:element name=”PageId”>
<xsl:value-of select=”$PageId”/>
</xsl:element>
<xsl:element name=”WebPartId”>
<xsl:value-of select=”$WebPartId”/>
</xsl:element>
<xsl:element name=”FeedPageUrl”>
<xsl:value-of select=”$FeedPageUrl”/>
</xsl:element>
<xsl:element name=”FeedEnabled”>
<xsl:value-of select=”$FeedEnabled”/>
</xsl:element>
<xsl:element name=”SiteUrl”>
<xsl:value-of select=”$SiteUrl”/>
</xsl:element>
<xsl:element name=”BlankTitle”>
<xsl:value-of select=”$BlankTitle”/>
</xsl:element>
<xsl:element name=”BlankGroup”>
<xsl:value-of select=”$BlankGroup”/>
</xsl:element>
<xsl:element name=”UseCopyUtil”>
<xsl:value-of select=”$UseCopyUtil”/>
</xsl:element>
<xsl:element name=”DataColumnTypes”>
<xsl:value-of select=”$DataColumnTypes”/>
</xsl:element>
<xsl:element name=”ClientId”>
<xsl:value-of select=”$ClientId”/>
</xsl:element>
</params>
<result>
<xsl:apply-templates/>
</result>
</xml-cqwp>
</xsl:template>
<xsl:template match=”*”>
<xsl:element name=”{name(.)}”>
<xsl:for-each select=”@*”>
<xsl:attribute name=”{name(.)}”><xsl:value-of select=”.”/></xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<!–
<xsl:template match=”@* | node()”>
<xsl:copy>
<xsl:apply-templates select=”@* | node()”/>
</xsl:copy>
</xsl:template>
–>
</xsl:stylesheet>

C’è un problema però, non basta questo file per estrarre l’XML, bisogna adottare un altro trucchetto, ho creato un secondo stylesheet xsl che ho chiamato Empty.xsl e che è fatto in questo modo:

<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:fo=”http://www.w3.org/1999/XSL/Format”>
<xsl:output method=”xml” version=”1.0″ encoding=”UTF-8″ indent=”yes”/>
</xsl:stylesheet>

Assegnando il primo file alla proprietà MainXslLink e il secondo alle proprietà ItemXslLink e HeaderXslLink si ottiene un xml di questo tipo:

<?xml version=”1.0″ encoding=”utf-8″?>
<xml-cqwp>
<params>
<cbq_isgrouping>false</cbq_isgrouping>
<cbq_columnwidth>100</cbq_columnwidth>
<Group/>
<GroupType/>
<cbq_iseditmode>true</cbq_iseditmode>
<cbq_viewemptytext>La query non ha restituito elementi. Per configurare la query per questa web part, &lt;a href=”#” onclick=”javascript:MSOTlPn_ShowToolPane2(’Edit’,'g_a3f67598_8486_4855_bbd1_47a052236458′);”&gt;aprire il riquadro Strumenti&lt;/a&gt;.</cbq_viewemptytext>
<SiteId>21eba696-36a0-4ad5-95e8-842c0fe0d0c4</SiteId>
<WebUrl>%2Fit%2Fatmnews%2Fatminforma</WebUrl>
<PageId>5c33b0e5-d576-4d0f-a6d5-afbac1bfdefb</PageId>
<WebPartId>a3f67598-8486-4855-bbd1-47a052236458</WebPartId>
<FeedPageUrl>/_layouts/feed.aspx?</FeedPageUrl>
<FeedEnabled>false</FeedEnabled>
<SiteUrl>http://admin.atm.it</SiteUrl>
<BlankTitle>(Vuoto)</BlankTitle>
<BlankGroup>(Vuoto)</BlankGroup>
<UseCopyUtil>false</UseCopyUtil>
<DataColumnTypes>;Modified,DateTime;Title,Text;Author,User;Editor,User;_Level,Number;Created,DateTime;{1d22ea11-1e32-424e-89ab-9fedbadb6ce1},Counter;FileRef,Lookup;Description,Note;PublishingRollupImage,Image;Comments,Note;</DataColumnTypes>
<ClientId>ctl00_SPWebPartManager1_g_a3f67598_8486_4855_bbd1_47a052236458</ClientId>
</params>
<result>
<dsQueryResponse>
<Rows>
<Row ListId=”{A898ACF6-7C42-441F-99A0-05D322E419EF}” WebId=”{AC38FAD2-8709-42EF-9FCF-7B4A822993A8}” ID=”1″ Title=”" FileRef=”en/giromilano/Pages/default.aspx” _x007B_1d22ea11_x002D_1e32_x002D_424e_x002D_89ab_x002D_9fedbadb6ce1_x007D_=”1″ Modified=”2009-02-06 23:38:26″ Author=”Account di sistema” Editor=”Account di sistema” Created=”2009-02-06 15:28:42″ PublishingRollupImage=”" _Level=”2″ Comments=”" LinkUrl=”http://admin.atm.it/en/giromilano/Pages/default.aspx” PubDate=”Fri, 06 Feb 2009 23:38:26 GMT” ImageUrl=”" ImageUrlAltText=”" Description=”" Style=”Default” GroupStyle=”DefaultHeader” __begincolumn=”True” __begingroup=”False”/>
<Row ListId=”{F7E2272E-75BF-435B-A467-59AEC5A0755C}” WebId=”{22DCC1AB-EE62-46E9-B020-E3D2C50DD325}” ID=”2″ Title=”La missione” FileRef=”en/ilgruppo/chisiamo/Pages/lamissione.aspx” _x007B_1d22ea11_x002D_1e32_x002D_424e_x002D_89ab_x002D_9fedbadb6ce1_x007D_=”2″ Modified=”2009-02-06 17:37:05″ Author=”Account di sistema” Editor=”Account di sistema” Created=”2009-02-06 16:06:02″ PublishingRollupImage=”" _Level=”2″ Comments=”" LinkUrl=”http://admin.atm.it/en/ilgruppo/chisiamo/Pages/lamissione.aspx” PubDate=”Fri, 06 Feb 2009 17:37:05 GMT” ImageUrl=”" ImageUrlAltText=”" Description=”" Style=”Default” GroupStyle=”DefaultHeader” __begincolumn=”False” __begingroup=”False”/>
</Rows>
</dsQueryResponse>
</result>
</xml-cqwp>

Con in mano l’xml prodotto posso finalmente lavora of-line per debuggare i miei stili persoinalizzati. Il prossimo passo sarà creare degli XSL personalizzati a partire dagli originali che siano usabili fuori dal contesto SharePoint, ovvero enibendo le funzioni custom di SharePoint del namespace “cmswrt“, in questo modo avrò piena liberta di esplorare la struttura e le logiche degli XSL. Senza però dar troppo peso al risultato.



domenica 1 febbraio 2009

SharePoint Manager 2007 - alla ricerca dei misteri di WSS e MOSS

Come da titolo il programma SharePoint Manager 2007 (SPM 2007) è un utilissimo tool disponibile su CodePlex che consente di ispezionare tutte le proprietà di SharePoint (sia WSS 3.0 che MOSS 2007). Con SPM 2007 è possibile vedere le Feature attivate sia a livello di Site Collection che a livello di Web, inoltre è possibile avere una visione completa della struttura del sito, dei folder creati (ad esempio “_catalog”) dei content type e delle colonne di sito. Di questi ultimi due oggetti SPM 2007 fornisce anche il codice XML che li descrive, in questo modo risulta veramente semplice estrarre le infoimzioni necessarie per riportare su file system quanto creato con l’interfaccia grafica di SharePoint, ovvero estrarre pezzi di codice CAML per replicare quanto fatto a mano in un progetto Visula Studio. Con questo tool ho avuto modo di scoprire quanto riportato in un post precedente, ovvero che SharePoint memorizzi in alcune proprietà, accessebile tramite SPWeb.AllProperties, i GUID delle liste create alla creazione del sito stesso. Con un po’ di intuito e spirito di osservazione è anche possibile scoprire dei veri e propri tesori, ovvero delle carattesristiche non documentate, che facilitano alcuni passi dello sviluppo, per esempio è possibile escludere un sito dalla Global Navigation semplicemente impostando un prorpietà tra quelle presenti in SPWeb.AllProperties:

// _GlobalNavigationExcludes property contains a delimited string of
// GUIDs identifying the Id of each site to be excluded from global
// navigation
webSite.AllProperties["__GlobalNavigationExcludes"]

Quindi impostando questa proprietà con un elenco di GUID separati da punto e virgola (;) si può escluderli dalla global navigation del sito in cui viene impostata la proprietà. Esiste anche la proprietà “__CurrentNavigationExcludes”, ma non l’ho provata. Sempre tramite SPM 2007 ho potuto ricavare utili informazioni per scrivere il codice personalizzato che genera Feed RSS per un sito di Paublishing, che ho già menzionato e che vi descriverò in seguito.
Spero di avervi dato informazioni utili e mi aspetto qualche commento di conferma su quanto detto o delle smentite se ho riportato informazioni errate. Di certo mi piacerebbe sapere se l’utilizzo diretto di queste proprietà ha qualche controindicazione.



Automate Web App Deployment with the SharePoint API

Segnalo un interessante articolo su MOSS 2007 “Automate Web App Deployment with the SharePoint API” !

sabato 24 gennaio 2009

Ringraziamenti

Voglio ringraziare Elisabetta Sasselli e Caludio Brotto di GreenTeam, con cui ho collaborato per un recente progetto e che mi hanno insegnato molto su SharePoint. Con la loro competenza e la loro passione mi hanno spinto inconsapevolmente ad iniziare questa avventura di blogger, facendomi apprezzare sempre più, sia il prodotto che gli sforzi fatti per impararlo.

GRAZIE.



giovedì 22 gennaio 2009

Feed RSS con SharePoint - 1/2

Usando il WCM di SharePoint mi sono dovuto occupare della gestione dei feed rss. SharePoint OOTB genera feed compatibili con la versione 2.0 di RSS (Specifiche RSS 2.0) usando, per quanto ho potuto vedere, due distinte pagine aspx:

  • Feed.aspx: usata dalle Content Query Web Part per esporre un feed rss dei risultati della query
  • ListFeed.aspx: usata delle liste per esporre un feed del loro contenuto

Come tutti gli strumenti OOTB, non sempre si adeguano alle esigenze di progetto, nel nostro caso (sito di publishing) i feed generati dalle liste non vanno bene, in quanto i link generati fanno riferimento agli item della lista stessa, i feed generati dalle CQWP andrebbero bene se non fosse che non si accordano con le specifiche grafiche. La bella notizia è che costruire un proprio feed RSS non è complicato, pertanto per soddisfare le esigenze di progetto ho implementato una mia pagina aspx da mettere nella cartella LAYOUTS di SharePoint. Di questo però parlerò un altro giorno, adesso scappo a dormire…



martedì 30 dicembre 2008

Accessibilità con SharePoint 2007

Avendo dovuto affrontare il discorso di sito accessibile, per un recente progetto, da realizzarsi con MOSS 2007, ho fatto un po’ di ricerche in giro per vedere come affrontare il progetto. Su CODEPLEX ho trovato alcuni interessanti progetti, uno tra tutti GSPTV, che mettevano a disposizioni soluzioni interessanti per rendere accessibili: webpart zone, menu di navigazione, box di ricerca, content query web part etc. In più ho trovato molto interessante il progetto ARF, anch’esso mette a disposizione sia controlli che adapter per sistemare alcune magagne di SharePoint. A dirla tutto, come consiglio, non ho usato un unico progetto, ma una selezione di componenti di uno e dell’altro. Di ARF in particolare ho trovato molto interessanti il ARF:Menu e ARF:SiteMap. Una delle caratteristiche principali di ARF (Alternative Render Framework) è di utilizzare il linguaggio XML per descrivere gli oggetti di MOSS e una serie di fogli di stile XSL per renderizzare il codice HTML. In questo modo il controllo in mano allo sviluppatore è completo.

Riferimenti

GSPTV
ARF



lunedì 29 dicembre 2008

Personalizzare Content by Query WebPart (CQWP) e Summary Link (SL) con DDWRT in SharePoint 2007

Dopo aver brevemente accennato all’esistenza del namespace “CMSWRT” negli stili xsl delle CQWP di SharePoint 2007 e al fatto che ci sono pochi riferimenti a riguardo, passiamo a vedere un namespace decisamente più utile. DDWRT è un namespace per XSL derivante da SharePont 2003, che può comunque essere riutilizzato anche all’interno dei file si stile XSL di SharePoint 2007. Questo nemaspace ci mette a disposizione molte utili funzioni (per un completo elenco delle funzionalità), tra le quali GetFileExtension() che estrae l’estensione di un file dalla URL e MapToIcon() che restituisce l’icona associata con l’estensione del file. Di seguito un breve esempio di codice utilizzato in uno dei miei XSL.

<div class=”docicon-link-item”>
<img class=”docicon” alt=”Type” src=”/_layouts/images/{ddwrt:MapToIcon(”, ddwrt:GetFileExtension(string($SafeLinkUrl)))}”/>
<a href=”{$SafeLinkUrl}” target=”{$LinkTarget}” title=”{@LinkToolTip}”>
<xsl:value-of select=”$DisplayTitle”/>
</a>
</div>

Il risultato finale è il link a un file con a sinistra l'icona del tipo di documento, recuperata in base all'estensione del documento stesso. Il nome dell'icona viene preso dal file xml DOCICON. Quindi se associo un'icona diversa ai file pdf (per esempio) vedrò la stessa icona mostrata nelle liste.

sabato 22 novembre 2008

Personalizzare le Content Query WebPart con i WebControl Runtime

Indagando sull varie possibilità di utilizzo delle Content Query WebPart e della personalizzazione dei risultati mediante stili XSL personalizzati, mi sono imbattuto nel namespace “CMSWRT”.

Tale namespace si riferisce alle classi contenute nel namespace .NET SharePoint.Publishing.WebControls.WebPartRuntime. A dire la verità ispezionando con l’Object Viewer di Visual Studio 2008 il namespace Microsoft.SharePoint.Publishing.WebControls non ho trovato nessun WebRunTime e neanche tramite SDK sono riuscito a trovare informazioni utili. L’unica cosa che ho notato è che negli stili XSL di CQWP e Summary Links le funzioni appartenenti a questa classe sono principalmente tre:

RegisterFeedUrl(string, string)
GetPublishingResource(string)
EnsureIsAllowedProtocol(string)

Queste funzione vengono usate per gestire un feed RSS nei risultati delle sopra citate WebPart.

Tag Technorati:

lunedì 17 novembre 2008

Recuperare gli ID delle liste di sistema

In SharePoint le liste hanno ID dinamici, cioè vengono creati quando le liste sono instanziate nel sito, quindi se si vuole accedere ad una lista applicativamente senza utilizzare il suo URL (che in sharepoint è localizzato) bisogna trovare un sistema per recuperare gli ID delle liste.
Fortunatamente SharePoint memorizza gli ID delle liste di sistema in un dictionary a livello di Web (SubSite): la proprietà in questione è SPWeb.AllProperties.
Per esempio per recuperare l’ID della lista “Site Collection Images” (presente in un Publishing Portal) si può usare codice seguente:
SPList SiteCollectionImagesList = web.Lists[new Guid(web.AllProperties["__SiteColImagesListId"].ToString())];