Masterpage Sharepoint - Alternative aux webparts

En parcourant les forums Sharepoint, j'ai constaté que certains visiteurs pensaient que la seule intégration possible de contrôles dans un environnement Sharepoint devait forcément passer par les webparts. Interloqué par cette interrogation, j'ai décidé de faire un article sur le sujet en prenant un exemple qui consiste à développer un contrôle serveur personnel (non webpart) que l'on va insérer dans la masterpage et qui affichera les N dernières annonces de la liste "Announcements". On pourrait tenter de faire quelque chose d'équivalent en utilisant Sharepoint Designer et en insérant notre liste "Announcements" dans la masterpage. Le seul problème avec cette technique est que les webparts de liste standards ne sont pas "partageables" entre plusieurs sites car ils pointent sur une liste d'un seul et même site or la masterpage est partagée et de ce fait, lorsque vous naviguez sur un autre site, le système plantera en vous disant que cette liste n'existe pas d'où l'intérêt d'éventuellement passer par la technique décrite dans ce tutoriel.

- Titre : Masterpage Sharepoint - Alternative aux webparts

- Parution : 20 août 2007

- Licence : Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Sommaire

- I. Introduction

- II. Webpart dans une masterpage?

- III. Web custom control - Contrôle serveur web personnel, qu'est-ce que c'est au juste?

- IV. Notre contrôle personnel dans la masterpage

- V. Création du projet dans Visual Studio

- VI. Référencement des namespaces nécessaires et héritage de la classe principale

- VII. Propriétés de notre contrôle

- VIII. Les deux méthodes principales à réécrire

- IX. Vérifier que l'utilisateur courant ait bien un accès en lecture à la liste d'annonces

- X. Interrogation de la liste d'annonces

- XI. Déploiement de notre contrôle dans la GAC et dans Sharepoint

- X-A. Déploiement du contrôle (la DLL) dans la GAC

- X-B. Marquer le contrôle comme "Safe" dans Sharepoint

- X-C. Insertion du contrôle dans la masterpage Sharepoint

- XII. Téléchargement

- XIIII. Conclusion

I - Introduction

Le but de cet article est de montrer une autre manière d'intégrer des contrôles personnels dans Sharepoint. La manière la plus fréquente est le développement de webparts que l' on intègre ensuite dans des pages. Pour toute information sur les webparts, vous pouvez consulter les tutoriaux suivants:

- Déploiement d'un webpart personnel dans Sharepoint

- Utilisation et connexion de WebParts

- Ecrire un webpart pour Sharepoint avec Smartpart

- Aller plus loin avec les webparts Sharepoint

Nous allons créer un contrôle personnel qui affiche les dernières annonces disponibles pour une collection de sites directement sur la masterpage. Pour ce faire, nous utiliserons un "web custom control" ASP.NET.

II - Webpart dans une masterpage?

C'est en parcourant les forums que je suis tombé sur l'une ou l'autre question qui évoquait la mise en place d'un webpart dans une masterpage. Les utilisateurs ne voyaient aucune possibilité d'insérer un webpart dans une masterpage et pour cause, il n'y a généralement pas de webpart zone dans une masterpage, ce qui rend impossible l'ajout d'un webpart. On peut cependant utiliser la barre d'outils "Webparts" de Sharepoint Designer pour accéder aux différents webparts disponibles et les insérer en faisant un glisser/déplacer dans la masterpage. Ceci dit, comme expliqué dans le synopsis, on peut rencontrer certaines limitations inhérentes aux webparts de liste standard comme par exemple la liste d'annonces. On peut facilement contourner ce problème en développant un contrôle personnel ou même un webpart personnel (je préfère la première solution) que l'on déploie ensuite dans la masterpage.

III - Web custom control - Contrôle serveur web personnel, qu'est-ce que c'est au juste?

Une alternative (plus simple d'ailleurs) aux webparts et probablement plus adaptée au contexte d'une masterpage est le développement d'un simple contrôle serveur. Sharepoint reposant sur ASP.NET, on peut facilement développer des contrôles tel qu'on le ferait en ASP.NET pour les utiliser dans Sharepoint par la suite. Un contrôle personnel n'est autre qu'un contrôle dans lequel on implémente "manuellement" le code behind qui sera ensuite utilisé pour générer le code client interprété par le navigateur. Plutôt que de créer une page ASPX avec le support de Visual Studio, on va créer une DLL que l'on référencera ensuite dans la masterpage utilisée par notre collection de sites Sharepoint.

IV - Notre contrôle personnel dans la masterpage

Afin que vous ayez une idée plus précise de ce que nous allons faire, voici une capture d'écran qui montre notre contrôle inséré dans une masterpage Sharepoint. Celui-ci affiche une liste de N annonces sous forme de liens cliquables qui redirigent le visiteur vers l'annonce complète où N correspond à la valeur attribuée à la propriété ItemLimit.

V - Création du projet dans Visual Studio

Pour créer un web custom control en dehors du contexte d'un site web, créez simplement un projet de type class library comme illustré ci-dessous

VI - Référencement des namespaces nécessaires et héritage de la classe principale

Notre contrôle devant s'exécuter dans un contexte web et devant interroger une liste Sharepoint, vous devez référencer ces deux DLL

- Microsoft.Sharepoint que vous pouvez trouver dans le répertoire ISAPI de votre installation Sharepoint

- System.Web que vous trouvez directement lorsque vous ajoutez une référence à votre projet comme illustré sur l'image ci-dessous

Lorsque vous avez ajouté les DLL, veuillez référencer les espaces de noms suivants:

- Microsoft.Sharepoint

- System.Web

- System.Web.UI

- System.Web.UI.WebControls

- System.Web.UI.HtmlControls

Vous disposez à présent de tous les espaces de noms requis pour pouvoir réaliser notre contrôle. Vous n'avez plus qu'une chose à faire, c'est de faire hériter notre classe principale de WebControl car notre contrôle sera un nouveau WebControl.

VII - Propriétés de notre contrôle

Afin de permettre plus de souplesse et notamment pour ne pas figer des informations telles que l'URL du site Sharepoint où se trouve la liste d'annonces, le nom de la liste d'annonces, nous allons passer par des propriétés. Celles-ci permettront à l'utilisateur du contrôle de spécifier les valeurs requises. Voici deux captures d'écran qui montrent comment ces propriétés peuvent être paramétrées par l'utilisateur

Dans Sharepoint Designer

Dans un projet web classique (vous pouvez bien sûr réutiliser ce contrôle dans un projet web normal)

Voici ce que ça donne au niveau du code

bool _TruncateTitle = false;
string _SiteURL = null;
string _AnnouncementList = null;
public bool TruncateTitle
{
get
{
return _TruncateTitle;
}
set
{
_TruncateTitle = value;
}
}
public string SiteURL
{
get
{
return _SiteURL;
}
set
{
_SiteURL = value;
}
}
public string AnnouncementList
{
get
{
return _AnnouncementList;
}
set
{
_AnnouncementList = value;
}
}
///....autres propriétés

VIII - Les deux méthodes principales à réécrire

Comme pour un webpart, il y a certaines méthodes à réécrire pour pouvoir générer nos sous contrôles et le rendu de ceux-ci.

Méthode

Description

CreateChildControls

Permet de créer ses sous-contrôles (label, textbox, button etc...)

Render

Permet de "rendre" le HTML de ces contrôles pour que le navigateur puisse les interpréter

CreateChildControls

protected override void CreateChildControls()
{
ErrorMessage = new Label();//Holds the error message if any
ErrorMessage.Style.Add(HtmlTextWriterStyle.Color, "red");
ContentTable = new HtmlTable();//Will contain all the announcements
ContentTable.Width = "100%";
ContentTable.Height = "100%";
ContentTable.Style.Add(HtmlTextWriterStyle.Overflow, "auto");
HtmlTableRow HeaderRow = new HtmlTableRow();
HtmlTableCell HeaderCell = new HtmlTableCell();
HeaderCell.InnerText = Title; //Announcement Title
HeaderRow.Cells.Add(HeaderCell);
ContentTable.Rows.Add(HeaderRow);
GetLatestAnnouncments();//Call to retrieve the announcements
this.Controls.Add(ContentTable);//Adding our table to the page controls
this.Controls.Add(ErrorMessage);//Adding our label to the page controls
}

- Nous créons un label qui affichera les messages d'erreurs en cas de problème

- Nous créons une table HTML qui contiendra toutes les annonces.

Render

protected override void Render(HtmlTextWriter writer)
{
EnsureChildControls();//Makes sure the controls are created before rendering them
if (ErrorMessage.Text == "") //If no error, display the announcements
{
ContentTable.RenderControl(writer);
}
else //else display the error message
{
ErrorMessage.RenderControl(writer);
}
}

- Nous appelons EnsureChildControls qui s'assure que les contrôles enfants sont bien créés.

- Nous utilisons la méthode RenderControl des contrôles pour générer le HTML.

IX - Vérifier que l'utilisateur courant ait bien un accès en lecture à la liste d'annonces

Une masterpage étant un objet utilisé par plusieurs sites/sous-sites, il est tout à fait possible qu'un utilisateur U ayant accès à un site S voie cette masterpage malgré le fait qu'il n'ait pas accès aux annonces que l'on met à disposition de tous. Nous devons donc vérifier au préalable si l'utilisateur courant a bien accès aux annonces ou pas et le cas échéant, ne rien afficher. Une technique permettant de le faire est la suivante:

try
{
TargetWeb.Lists[AnnouncementList].CheckPermissions(SPBasePermissions.ViewListItems);
}
catch
{
CanReadItems = false;
}

La méthode CheckPermissions lance une exception au cas où l'utilisateur courant n'a pas l'accès passé en paramètre. Ce n'est pas très élégant car il eut été préférable que cette méthode renvoie un true ou false. Donc, en cas de non accès, le code branchera le catch dans lequel vous pourrez mettre un booléen à "false". Notez qu'il est possible d'empêcher le système de générer cette exception mais dans le cas qui nous occupe, ce n'est pas nécessaire.

X - Interrogation de la liste d'annonces

Pour pouvoir récupérer les annonces présentes dans notre liste, nous devons bien sûr interroger celle-ci.

try
{

SPQuery AnnouncementQuery = new SPQuery();
AnnouncementQuery.Query = "<OrderBy><FieldRef Name='Modified' Ascending='FALSE' /></OrderBy>";
AnnouncementQuery.ViewFields = "<FieldRef Name='LinkTitleNoMenu' /><FieldRef Name='" +
TargetWeb.Lists[AnnouncementList].Fields["Encoded Absolute URL"].InternalName + "' />";
AnnouncementQuery.RowLimit = (uint)ItemLimit;
foreach (SPListItem AnnItm in TargetWeb.Lists[AnnouncementList].GetItems(AnnouncementQuery))
{
HtmlTableRow ItmRow = new HtmlTableRow();
HtmlTableCell ItmCell = new HtmlTableCell();
ItmCell.InnerHtml = "<a href='" + AnnItm["Encoded Absolute URL"].ToString().Substring(0,
AnnItm["Encoded Absolute URL"].ToString().LastIndexOf("/") + 1) + "DispForm.aspx?ID=" +
AnnItm.ID + "'>" + AnnItm["LinkTitleNoMenu"].ToString() + "</a>";
ItmRow.Cells.Add(ItmCell);
ContentTable.Rows.Add(ItmRow);
}

}
catch (Exception Ex)
{
ErrorMessage.Text = Ex.Message;
}

- On crée une CAML query via la classe SPQuery en sélectionnant toutes les annonces triées ordre décroissant de leur date de création

- On dit que les champs à inclure sont LinkTitleNoMenu et Encoded Absolute URL qui représente l'URL vers l'annonce

- On dit que la limite du nombre de lignes devant être retournées correspond à la propriété ItemLimit

- On parcourt le résultat retourné par la SPQuery et on crée nos lignes/cellules de tableau permettant d'afficher l'information

XI - Déploiement de notre contrôle dans la GAC et dans Sharepoint

X-A - Déploiement du contrôle (la DLL) dans la GAC

Pour déployer la DLL dans la GAC, suivez les instructions dans ce tutoriel. La marche à suivre est identique, il est donc inutile de répéter les instructions ici.

X-B - Marquer le contrôle comme "Safe" dans Sharepoint

Afin que le contrôle soit reconnu comme sûr dans Sharepoint, récupérez sa signature via Reflector (également mentionné dans le lien vers le tuto ci-dessus) et ensuite éditez le web.config de votre application Sharepoint et placez-y le code suivant dans la section <SafeControls>

<SafeControl Assembly="AnnoucementBanners, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3bb84b5ba42087a0" Namespace="AnnoucementBanners" TypeName="*" Safe="True" />

X-C - Insertion du contrôle dans la masterpage Sharepoint

Pour éditer la masterpage, vous pouvez ouvrir Sharepoint designer, ouvrir le site de votre choix, naviguer dans "catalogs" et ensuite choisir la masterpage de votre choix. Vous pouvez également utiliser la galerie de masterpage comme illustré ci-dessous.

Ensuite, lorsque vous êtes en mode édition dans Sharepoint designer, passez en mode code et enregistrez le contrôle via une directive Register.

Exemple de propriété

<%@ Register TagPrefix="Announcement" Namespace="AnnoucementBanners" Assembly="AnnoucementBanners, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3bb84b5ba42087a0" %>

Ensuite, à l'endroit où vous voulez afficher le contrôle, écrivez ces lignes de code

Comme vous le constatez, nous retrouvons nos propriétés AnnoucementList etc.. exposées par notre contrôle. Vous n'avez plus qu'à enregistrer les modifications apportées à la masterpage et à publier celle-ci afin que tous les visiteurs puissent bénéficier de ce contrôle. Vous pouvez tester en vous authentifiant avec des utilisateurs dont certains ont accès à la liste et pas d'autres et vous verrez que le contrôle s'adaptera en fonction du contexte.

XII - Téléchargement

Vous pouvez télécharger l'exemple complet décrit dans cet article ici

XIIII - Conclusion

Les contrôles web personnels sont une solution d'intégration non négligeable pour Sharepoint car ils incluent bien sûr du code behind et peuvent s'intégrer à la manière des webparts dans des pages, masterpage.