SharePoint et les technologies 3.5 - Part I

Stéphane Eyskens

Le train technologique poursuivant sa course effreinée, voici un tutoriel qui se décline en plusieurs parties pour aborder l'utilisation de dotnet 3.5 au sein de SharePoint. La première partie se concentre sur la configuration de SharePoint et sur l' utilisation de l'AJAX dans des WebParts. La deuxième partie s'attardera sur Silverlight et la troisième abordera l'utilisation de WCF.

- Titre : SharePoint et les technologies 3.5 - Part I

- Auteur : Stéphane Eyskens

- Parution : 25 janvier 2009

- Licence : Copyright ®  Developpez. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Configuration de SharePoint

- III. Le ScriptManager et les pages maîtres

- IV. Les techniques d'intégration de l'AJAX dans les composants SharePoint

- IV-A. Dans les WebParts, les contrôles web, les colonnes personnelles

- IV-B. Dans les pages applicatives

- IV-C. Dans les workflows

- V. Création d'un SPGridView avec de l'AJAX - Tout en Code-Behind

- VI. Utilisation de l'AjaxControlToolkit dans un contrôle utilisateur

- VII. Tester les projets présents en téléchargement

- VIII. Téléchargement

I - Introduction

Avant toute chose, les pré-requis pour pouvoir reproduire ce qui est décrit dans le tutoriel sont les suivants :

- Le framework 3.5 doit être installé sur le serveur

- Vous disposez de MOSS ou WSS avec le SP1 installé

- Vous disposez de Visual Studio 2005 ou 2008

La plate-forme dotnet évoluant sans cesse et SharePoint étant entièrement basé sur celle-ci, il est important de comprendre comment intégrer les dernières évolutions technologiques. Une des évolutions apportées par le framework 3.5 est l'intégration native d'ASP.NET AJAX dans les DLL du framework.

Avant, vous deviez télécharger les extensions AJAX et les installer en plus du framework .NET. Nous allons voir comment configurer et utiliser ces librairies 3.5 au sein de composants SharePoint

II - Configuration de SharePoint

Pour commencer, il faut rendre SharePoint compatible avec le framework 3.5. Etant donné que Tobias Zimmergren a déjà entièrement décrit comment s'y prendre, je vous renvoie vers son blog qui explique en détail ce qui doit être ajouté dans le web.config de l'application SharePoint pour laquelle vous souhaitez utiliser 3.5.

Vous pouvez également télécharger la fonctionnalité développée par Renaud Comte permettant d'effectuer les modifications requises dans le web.config automatiquement. Elle s'intitule 3.5 Web.Config Feature (separate download) et permet d'ajouter les sections nécessaires dans le fichier web.config de l'application SharePoint que vous souhaitez rendre compatible.

Enfin, à toutes fins utiles, je vous ai joint un exemple de web.config fonctionnel et compatible avec 3.5. Vous le trouverez dans la section téléchargement.

III - Le ScriptManager et les pages maîtres

L'objectif du tutoriel n'est pas de vous apprendre comment utiliser l'AJAX en ASP.NET mais bien d'aborder tant que faire se peu les spécificités liées à SharePoint. Une de ces spécificités réside notamment dans l'utilisation des ScriptManager.

Comme vous le savez sans doute, une instance de l'objet ScriptManager est impérative pour pouvoir travailler en AJAX. Généralement, c'est d'ailleurs le premier contrôle qui doit être ajouté à une page. Dans SharePoint, les composants web sont toujours exécutés dans un contexte où une page maître est présente. En effet, qu'il s'agisse de WebParts, colonnes personnelles, web controls etc...tous ces composants sont encapsulés dans l'architecture SharePoint et bénéficient automatiquement de la présence de la page maître associée au site où ils sont exécutés.

Grâce ou à cause de cela, la déclaration du ScriptManager se fait généralement au sein de la page maître elle-même, comme ceci :

<asp:ScriptManager id="ScriptManager1" EnablePartialRendering="TRUE" runat="server">

Au cas où vous ne bénéficiez pas d'une page maître avec un ScriptManager intégré (ce qui est le cas avec les pages maîtres standard), vous pouvez en déployer une vous-même. C'est ce que j'ai fait pour cet exemple, vous retrouverez une page maître qui sera ajoutée dans la galerie de pages maîtres lors de l'activation de la fonctionnalité liée au projet.

Vous pourrez donc vous inspirer de cela pour développer vos propres pages maîtres ou en modifier une existante avec SharePoint Designer par exemple.

IV - Les techniques d'intégration de l'AJAX dans les composants SharePoint

IV-A - Dans les WebParts, les contrôles web, les colonnes personnelles

Il existe globalement deux techniques majeures pour intégrer de l'AJAX dans les WebParts :

- Dans le code-behind du contrôle lui même : cette technique a le désavantage de "mélanger" le code métier avec l'interface graphique si on n'y prend garde

- Dans un contrôle utilisateur ASP.NET : cette technique isole l'aspect graphique dans le contrôle utilisateur. Il faut ensuite charger celui-ci dans notre WebPart

Une déclinaison de la deuxième technique consiste à utiliser le composant de Jan Tielens, j'ai nommé le Return of SmartPart qui a été récemment mis à jour par son auteur.

IV-B - Dans les pages applicatives

Les pages applicatives étant liées à la page maître Application.master, l'insertion du ScriptManager peut-être rendue plus complexe car il n'est pas évident de personnaliser cette page maître. Ceci dit, trois choix s'offrent néanmoins à vous :

- Vous personnalisez Application.master : en ajoutant la déclaration du script manager mais en acceptant toutes les contraintes liées à la personnalisation de cette page (voir google).

- Vous délivrez votre propre page maître applicative : vous liez explicitement vos pages applicatives à votre page maître applicative personnelle

- Vous générez le code AJAX "à la main" :en fonction de l'environnement et de la complexité de la page, c'est une option envisageable. L'avantage d'ailleurs de cette technique est qu'elle ne nécessite aucune configuration spécifique au niveau du serveur.

IV-C - Dans les workflows

Les seuls composants nécessitant éventuellement de recourir à l'AJAX sont les formulaires d'association/initiation/modification des workflows. Si vous utilisez Forms Services, bonne nouvelle : l'AJAX y est intégré nativement sans que vous n'ayez rien à faire. Si vous utilisez des pages web classiques, vous pouvez soit utiliser le mode déclaratif d'ASP.NET, soit générer dynamiquement les contrôles dans le code-behind associé à la page.

V - Création d'un SPGridView avec de l'AJAX - Tout en Code-Behind

Dans la lignée de mon dernier article sur le SPGridView, voici un WebPart qui utilise un SPGridView avec de la pagination bénéficiant de l'AJAX pour éviter un full page postback lorsque l'on passe d'une page à l'autre.

Voici pas à pas comment il faut s'y prendre avec Visual Studio 2008, notez que vous pouvez exécuter les mêmes étapes avec Visual Studio 2005

Créer un nouveau projet de type Class Library

Ajoutez ensuite les références suivantes :

1. System.Web => onglet dotnet

2. System.Web.Extensions => onglet dotnet

3. Microsoft.SharePoint => 12\ISAPI de SharePoint

Signez votre projet : Cliquez sur votre Projet => Propriétés => Onglet Signature => Signez le

Créez à présent une structure de répertoires et de fichiers comme illustré ci-dessous :

et renommez class1.cs en SPGridViewAjax.cs.

Voici à présent le contenu du fichier feature.xml :

<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="EE4B04A2-71A0-46E3-BA2A-783B0729DB3C"
Title="SPGridView avec de l'AJAX"
Description="SPGridView avec de l'AJAX"
Version="1.0.0.0"
Hidden="FALSE"
Scope="Site"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="webpart.xml"/>
</ElementManifests>
</Feature>

Fichier classique définissant une fonctionnalité de collection et pointant vers le fichier webpart.xml

Contenu du fichier webpart.xml :

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="WebParts"
List="113"
Url="_catalogs/wp"
RootWebOnly="TRUE">
<File Url="DVP.SPGridViewAJAX.webpart" Type="GhostableInLibrary" >
<Property Name="Group" Value="DVP - SPGridView"></Property>
</File>
</Module>
</Elements>

Ce fichier indique qu'il faut déployer le WebPart dans la galerie de WebParts de la collection où la fonctionnalité est activée.

Contenu du fichier DVP.SPGridViewAJAX.webpart :

<?xml version="1.0" encoding="utf-8"?>
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="signature" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="Title" type="string">DVP.SPGridViewAJAX.webpart</property>
</properties>
</data>
</webPart>
</webParts>

Veillez à remplacer signature par votre signature que vous pouvez obtenir avec Reflector. Ce fichier indique simplement au système que le WebPart est lié au contrôle spécifié par la signature.

Reprenez à présent votre classe principale que vous avez nommé SPGridViewAjax.cs et faites-là dériver de System.Web.UI.WebControls.WebParts.WebPart. Ensuite, déclarez deux membres de classe comme suit :

SPGridView SimpleGrid = null;
UpdatePanel ControlPanel = null;

réécrivez à présent la méthode CreateChildControls()

protected override void CreateChildControls()
{
ScriptManager ScriptMgr = ScriptManager.GetCurrent(Page);
if (ScriptMgr == null)
{
throw new ApplicationException("Pas de script manager!");
}
ControlPanel = new UpdatePanel();
ControlPanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
ControlPanel.ID = "ControlPanel";
Controls.Add(ControlPanel);
SimpleGrid = new SPGridView();
SPDataSource Donnees = new SPDataSource();
Donnees.List = SPContext.Current.Web.Lists["Documents"];
Donnees.Scope = SPViewScope.Recursive;
SimpleGrid.AutoGenerateColumns = false;
BoundField ColonneID = new BoundField();
ColonneID.DataField = "ID";
ColonneID.HeaderText = "ID";
SimpleGrid.Columns.Add(ColonneID);
BoundField ColonneTitre = new BoundField();
ColonneTitre.DataField = "Title";
ColonneTitre.HeaderText = "Title";
SimpleGrid.Columns.Add(ColonneTitre);
SimpleGrid.DataSource = Donnees;
SimpleGrid.AllowPaging = true;
SimpleGrid.PageSize = 1;
SimpleGrid.PageIndexChanging += new GridViewPageEventHandler(SimpleGrid_PageIndexChanging);
ControlPanel.ContentTemplateContainer.Controls.Add(SimpleGrid);
SimpleGrid.TemplateControl = null;
SimpleGrid.PagerTemplate = null;
ScriptMgr.RegisterAsyncPostBackControl(SimpleGrid);
base.CreateChildControls();
}

Ce SPGridView est lié à la liste Documents du site courant et aux colonnes ID et Title. Vous devez éventuellement changer le nom de la liste pour que ça fonctionne chez vous et si vous êtes en français, remplacez Title par Titre...Tout ceci peut bien sûr être fait dynamiquement dans le code mais je préfère simplifier au maximum la lisibilité, c'est pourquoi il n'y a pas de gestion d'erreurs non plus.

Au niveau de l'AJAX, le code détecte d'abord si un ScriptManager est présent ou non dans le contexte courant et lance une exception si aucun ScriptManager n'est trouvé. Ensuite, un UpdatePanel est créé et le SPGridView lui est ajouté en tant que contrôle.

Le SPGridView étant un contrôle très sensible, il faut lui spécifier que nous ne développons pas de modèle de pagination via la ligne de code :

SimpleGrid.PagerTemplate = null;

sauf si bien sûr vous souhaitez en créer un :). Complétons à présent avec les deux méthodes manquantes :

void SimpleGrid_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
SimpleGrid.PageIndex = e.NewPageIndex;
SimpleGrid.DataBind();
ControlPanel.Update();
}
protected override void OnPreRender(EventArgs e)
{
SimpleGrid.DataBind();
base.OnPreRender(e);
}

La méthode SimpleGrid_PageIndexChanging est appelée lors du click sur un numéro de page. Elle spécifie le nouvel index de page et raffraîchit l'UpdatePanel.

Le code complet est donc le suivant :

public class SPGridViewAjax : System.Web.UI.WebControls.WebParts.WebPart
{
SPGridView SimpleGrid = null;
UpdatePanel ControlPanel = null;
protected override void CreateChildControls()
{
ScriptManager ScriptMgr = ScriptManager.GetCurrent(Page);
if (ScriptMgr == null)
{
throw new ApplicationException("Pas de script manager!");
}
ControlPanel = new UpdatePanel();
ControlPanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
ControlPanel.ID = "ControlPanel";
Controls.Add(ControlPanel);
SimpleGrid = new SPGridView();
SPDataSource Donnees = new SPDataSource();
Donnees.List = SPContext.Current.Web.Lists["Documents"];
Donnees.Scope = SPViewScope.Recursive;
SimpleGrid.AutoGenerateColumns = false;
BoundField ColonneID = new BoundField();
ColonneID.DataField = "ID";
ColonneID.HeaderText = "ID";
SimpleGrid.Columns.Add(ColonneID);
BoundField ColonneTitre = new BoundField();
ColonneTitre.DataField = "Title";
ColonneTitre.HeaderText = "Title";
SimpleGrid.Columns.Add(ColonneTitre);
SimpleGrid.DataSource = Donnees;
SimpleGrid.AllowPaging = true;
SimpleGrid.PageSize = 1;
SimpleGrid.PageIndexChanging += new GridViewPageEventHandler(SimpleGrid_PageIndexChanging);
ControlPanel.ContentTemplateContainer.Controls.Add(SimpleGrid);
SimpleGrid.TemplateControl = null;
SimpleGrid.PagerTemplate = null;
ScriptMgr.RegisterAsyncPostBackControl(SimpleGrid);
base.CreateChildControls();
}
void SimpleGrid_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
SimpleGrid.PageIndex = e.NewPageIndex;
SimpleGrid.DataBind();
ControlPanel.Update();
}
protected override void OnPreRender(EventArgs e)
{
SimpleGrid.DataBind();
base.OnPreRender(e);
}
}

Le résultat ressemble à ceci :

avec une pagination en AJAX. Vous pouvez retrouver ce projet et une solution .wsp dans la section téléchargement.

Pour déployer le projet, je vous conseille d'utiliser l'add-in WSPBuilder pour Visual Studio

VI - Utilisation de l'AjaxControlToolkit dans un contrôle utilisateur

Pour illustrer l'utilisation de l'AjaxControlToolkit, j'ai décidé de reproduire l'exemple de Microsoft disponible ici. La seule différence est que cet exemple est dans un contexte web classique, je l'ai simplement remis dans le contexte de SharePoint.

Ajoutez ensuite les références suivantes :

1. System.Web => onglet dotnet

2. System.Web.Extensions => onglet dotnet

3. AjaxControlToolkit

La DLL AjaxControlToolkit est disponible sur le site de l'éditeur.

Comme pour l'exemple précédent, créez un projet de type Class Library et nommez-le DVP.AjaxToolkit.Exemples. Créez ensuite la structure de répertoire et de fichier suivante :

Excluez toutefois les fichiers dvp.master et master.xml qui servent à déployer une page maître. Je les ai inclus dans le projet afin que vous puissiez plus facilement tester les WebParts. Ceci dit, je vous laisserai découvrir par vous même comment cela a été fait.

Les fichiers feature.xml, webpart.xml et AjaxToolkitDvp.webpart sont très similaires à ceux de l'exemple précédent. Il est donc inutile d'en réafficher le contenu. Concentrons nous plutôt sur ce qui change réellement, à savoir la création d'un contrôle utilisateur.

Dans la structure du projet et plus précisémment dans le répertoire CONTROLTEMPLATES/DvpAjaxToolkit, il y a le contrôle utilisateur dvpajaxtoolkit.ascx. Celui-ci contient principalement le code suivant :

<%@ Control Language="C#"
Inherits="DVP.AjaxToolKit35.Exemples.AjaxToolkitExe....."
<%@ Register Tagprefix="cc1"
Namespace="AjaxControlToolkit" Assembly="AjaxControlToolkit...."

A savoir les directives déclarant l'utilisation du toolkit et le fait que la page dérive de AjaxToolkitExempleCodeBehind (que nous implémenterons plus tard). J'ai volontairement abrégé la déclaration des directives, vous pourrez les retrouver au complet en téléchargeant l'exemple.

En plus des directives, le contrôle contient une déclaration de style contenant toutes les classes CSS utilisées par le contrôle de rating.

<style type="text/css">
.accordionHeader
{
border: 1px solid #2F4F4F;
color: white;
background-color: #2E4d7B;
font-family: Arial, Sans-Serif;
font-size: 12px;
font-weight: bold;
padding: 5px;
margin-top: 5px;
cursor: pointer;
}

.accordionContent
{
background-color: #D3DEEF;
border: 1px dashed #2F4F4F;
border-top: none;
padding: 5px;
padding-top: 10px;
}

.ratingStar {
font-size: 0pt;
width: 13px;
height: 12px;
margin: 0px;
padding: 0px;
cursor: pointer;
display: block;
background-repeat: no-repeat;
}

.filledRatingStar {
background-image: url(PublishingImages/FilledStar.png);

}

.emptyRatingStar {
background-image: url(PublishingImages/EmptyStar.png);
}

.savedRatingStar {
background-image: url(PublishingImages/SavedStar.png);
}
</style>

Notez qu'il est préférable d'inclure les styles dans un fichier CSS à part que l'on déploiera ensuite dans une style library.

Ensuite vient le plus important, à savoir la déclaration du contrôle de rating :

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div style="float: left; width:230;">How much do you like ASP.NET AJAX ?</div>
<cc1:Rating ID="LikeRating" runat="server"
CurrentRating="3"
MaxRating="5"
StarCssClass="ratingStar"
WaitingStarCssClass="savedRatingStar"
FilledStarCssClass="filledRatingStar"
EmptyStarCssClass="emptyRatingStar"
OnChanged="LikeRating_Changed"
style="float: left;">
</cc1:Rating>
<br />
<div style="clear:left;">
<br />
<asp:Button ID="ButtonSubmit" runat="server" Text="Submit"
onclick="ButtonSubmit_Click" /><br /><br />
<asp:Label ID="LabelResponse" runat="server" Text="[ No response provioded yet.]"></asp:Label>
</div>
</ContentTemplate>
</asp:UpdatePanel>

Ici on a simplement la déclaration de l'UpdatePanel et du contrôle de Rating. C'est un copier-coller pur et simple de l'exemple proposé par Microsoft. Ce contrôle fait appel à la méthode LikeRating_Changed et le bouton de soumission appelle quant à lui la méthode ButtonSubmit_Click. Ces deux méthodes sont implémentées dans le code-behind du contrôle utilisateur. C'est la classe AjaxToolkitExempleCodeBehind dont voici le contenu :

public class AjaxToolkitExempleCodeBehind : System.Web.UI.UserControl
{
protected Rating LikeRating;
protected Label LabelResponse;

protected void LikeRating_Changed(object sender, AjaxControlToolkit.RatingEventArgs e)
{
e.CallbackResult = "Upate done. Value = " + e.Value + " Tag = " + e.Tag;
}
protected void ButtonSubmit_Click(object sender, EventArgs e)
{
string howMuch = "[unknown]";

switch (LikeRating.CurrentRating)
{
case 1:
howMuch = "a bit.";
break;
case 2:
howMuch = "some.";
break;
case 3:
howMuch = "a fair bit.";
break;
case 4:
howMuch = "a lot.";
break;
case 5:
howMuch = "more than any thing.";
break;
}

LabelResponse.Text = "You like ASP.NET AJAX " + howMuch + ".";
}
}

Ici, la différence par rapport à l'exemple de Microsoft est que ce code est inclut dans une classe dérivant de UserControl. LikeRating et LabelResponse sont déclarés en protected et correspondent aux contrôles déclarés de manière déclarative...

Enfin, il ne reste plus à notre WebPart SharePoint qu'à charger ce contrôle utilisateur. C'est la classe WebPartPrincipal.cs qui se charge de cela :

public class WebPartPrincipal : System.Web.UI.WebControls.WebParts.WebPart
{
const string ControlFile = @"/_controltemplates/dvpajaxtoolkit/dvpajaxtoolkit.ascx";

protected override void CreateChildControls()
{
ScriptManager ScriptMgr = ScriptManager.GetCurrent(Page);
if (ScriptMgr == null)
{
throw new ApplicationException("Pas de script manager");
}
else if (!ScriptMgr.EnablePartialRendering)
{
ScriptMgr.EnablePartialRendering = true;
}
UserControl Ctrl = Page.LoadControl(ControlFile) as UserControl;
Controls.Add(Ctrl);
base.CreateChildControls();
}
}

Le WebPart exécute le même test que pour l'exemple précédent pour détecter si un ScriptManager est bien présent ou non. Il fait également en sorte que la propriété EnablePartialRendering soit bien mise à TRUE sans quoi les changements ne seraient pas reflétés au sein du contrôle utilisateur.

Ensuite, le WebPart charge simplement le contrôle pointé par la constante ControlFile. Tout ceci donne le résultat suivant :

Pour déployer le projet, je vous conseille d'utiliser l'add-in WSPBuilder pour Visual Studio

VII - Tester les projets présents en téléchargement

Pour tester les projets proposés en téléchargement, commencez par déployer la solution DVP.AjaxToolKit35.Exemples.wsp via stsadm. Ensuite, après activation de la fonctionnalité de collection :

Vous devriez retrouver une nouvelle page maître que vous pouvez associer à votre site :

Ensuite, il ne vous reste plus qu'à ajouter le WebPart à une page :

Ensuite, vous pouvez déployer l'autre solution DVP.Ajax35.Exemples.wsp. Après activation de la fonctionnalité :

et ajouter le WebPart contenant le SPGridView avec pagination.

Veillez à le déployer dans un site où il existe une bibliothèque de documents nommées Documents avec une colonne Title. Sinon changez simplement le code et mettez le nom de la bibliothèque que vous voulez.

VIII - Téléchargement

Retrouvez les deux projets présentés dans le tutoriel ainsi que les solutions .wsp :

L'exemple avec le toolkit qui contient également la page maître
L'exemple qui contient le SPGridView avec de l'AJAX