Nous allons voir au travers d’un exemple complet comment créer et déployer un EventHandler dans Windows SharePoint Services 3.0. Les EventHandlers sont une nouveauté de WSS 3.0 et permettent d’être notifiés par WSS et d’agir sur certains évènements.
Il est possible de créer des EventHandlers sur tous les types de listes WSS. Pour notre exemple, nous allons créer, pas à pas, un EventHandler destiné à intercepter la création et la mise à jour d’un contact dans une liste de contacts standard WSS. Cet EventHandler aura comme tâche de calculer la valeur du champ « Full Name » présent par défaut sur les listes de contacts. Si cette valeur n’a pas été remplie par l’utilisateur, le handler se chargera de le faire à partir des valeurs des colonnes « FirstName » et « LastName » de manière à obtenir FullName = LastName, FirstName.
Remarque :
Certains d’entre vous doivent commencer à émettre des remarques : « Moi, dans mes listes de contacts, je n’ai pas les colonnes dont il parle ! ». En effet, les colonnes que j’ai citées précédemment sont en Anglais. Dans la version française de SharePoint Services, les mêmes colonnes sont nommées … en français. De plus, le nom visible des colonnes n’est pas toujours (et notamment pour les colonnes par défaut) le même que le nom réel de la colonne. Le tableau ci-dessous donne la correspondance entre le nom visible des colonnes que je vais manipuler et leur nom réel
Tableau de correspondance du nommage des colonnes avec WSS 3.0 US
|
Nom visible |
Nom réel |
|
First name |
FirstName |
|
Last name |
Title |
|
Full name |
FullName |
|
|
|
Pourquoi la remarque ci-dessus a-t-elle autant d’importance ? C’est simple : lorsque nous allons chercher à lire la valeur d’un champ d’un contact (ou écrire dans ce champ), nous allons devoir identifier ce champ et pour cela, il n’existe qu’une solution : l’identifier avec son nom EXACT ! Comme j’utilise une version US de WSS, j’utiliserai donc dans les exemples de code qui suivent le nommage des colonnes US.
Le moment venu, je vous montrerai une astuce pour lister le nom de colonnes existantes sur la liste.
Il est très facile de créer un EventHandler pour WSS 3.0. Commençons par créer un nouveau projet de type Class Library avec Visual Studio 2005. Dans mon exemple, le projet se nomme Bewise.Wss3.Sample.EventHandler. La première chose à faire est de signer le projet. En effet, une des contraintes fortes des EventHandler est qu’ils doivent être déployés dans le GAC et donc, signés. Ajoutez ensuite une référence vers la dll Microsoft.SharePoint (Dans le cas d’une installation par défaut de WSS 3.0, cette dll est stockée dans le répertoire C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI).
Nous allons maintenant créer le Handler proprement dit. Pour cela, je vais renommer la classe Class1 créée par défaut par Visual Studio en FullNameContactHandler. Tout le reste se passe dans le code de cette classe.
Je rajoute tout d’abord une clause using permettant de référencer l’assembly Microsoft.SharePoint. Ensuite, je modifie la déclaration de ma classe pour la faire hériter de la classe SPItemEventReceiver. Cette classe va me permettre de créer un EventHandler capable d’agir sur des évènements d’items (création, modification, …).
Je vais ensuite surcharger les méthodes de la classe SPItemEventReceiver correspondant aux événements sur lesquels je souhaite que mon handler réagisse, à savoir, la création et la mise à jour d’un contact. Les deux méthodes concernées sont ItemAdding et ItemUpdating.
Remarque :
Il existe également les méthodes ItemAdded et ItemUpdated. A la différence des méthodes que nous allons utiliser, et d’une manière plus générale, les méthodes en « ed » sont asynchrones. Elles sont déclenchées à la fin du traitement standard fait par WSS. Les méthodes en « ing » sont, elles, synchrones et permettent d’annuler le traitement (création, mise à jour, …).
Après avoir réalisé ces étapes, nous obtenons le code suivant :
using System;
using Microsoft.SharePoint;
namespace Bewise.Wss3.Sample.EventHandler
{
public class FullNameContactHandler : SPItemEventReceiver
{
public override void ItemAdding(SPItemEventProperties properties)
{
}
public override void ItemUpdating(SPItemEventProperties properties)
{
}
}
}
Nous allons maintenant pouvoir mettre en place l’intelligence de notre Handler. Comme le traitement à réaliser lors de la création et de la mise à jour est le même, je vais créer une fonction ComputeFullName qui se chargera de calculer le nom complet. Il ne me restera ensuite plus qu’à l’appeler depuis chacun des événements avec les bons paramètres. Voici ci-dessous le code de cette fonction
public String ComputeFullName(String firstName,
String lastName,
String fullName)
{
if (String.IsNullOrEmpty(fullName))
return String.Format("{0}, {1}", lastName, firstName);
else
return fullName;
}
Cette fonction attend en paramètre le prénom, le nom et le nom complet. Si le nom complet est null, alors la fonction retourne la concaténation du prénom et du nom séparé par une virgule. Dans le cas contraire, elle retourne la valeur du nom complet.
Maintenant, il faut nous charger d’appeler la méthode ComputeFullName lors de la notification de création et de mise à jour. Il va donc falloir, dans chacune de ces méthodes, récupérer les valeurs entrées par l’utilisateur WSS dans les champs prénom, nom et nom complet. Ensuite, nous appellerons la fonction ComputeFullName en lui passant ces valeurs et nous réaffecterons le résultat au champ nom complet.
Pour accéder aux valeurs des champs d’un Item, chaque événement fournit en paramètre un objet de type SPItemEventProperties. Cet objet contient 2 collections intéressantes :
· BeforeProperties : Collection des valeurs des champs avant la mise à jour (valeurs d’origine)
· AfterProperties : Collections des valeurs courantes des champs.
Pour récupérer la valeur de la colonne First Name, il me suffit donc de récupérer dans la collection AfterProperties, la valeur de la colonne First Name et ainsi de suite. Idem pour modifier la valeur d’un champ. Il suffit de modifier la valeur du champ dans la collection AfterProperties. Voici ci-dessous le code complet permettant de récupérer les valeurs nécessaires à l’appel de la fonction ComputeFullName et l’affectation du résultat au champ Full Name.
public override void ItemAdding(SPItemEventProperties properties)
{
String firstName = null;
String lastName = null;
String fullName = null;
firstName = properties.AfterProperties["FirstName"].ToString();
lastName = properties.AfterProperties["Title"].ToString();
fullName = properties.AfterProperties["FullName"].ToString();
fullName = ComputeFullName(firstName, lastName, fullName);
properties.AfterProperties["FullName"] = fullName;
}
Remarque :
Lorsque vous souhaitez lire ou écrire une valeur dans la collection, vous pouvez remarquer que le champ ciblé est identifié par son nom : soyez donc vigilant lors de l’écriture de ces noms.
Voici donc le code complet de notre Handler
using System;
using Microsoft.SharePoint;
namespace Bewise.Wss3.Sample.EventHandler
{
public class FullNameContactHandler : SPItemEventReceiver
{
public override void ItemAdding(SPItemEventProperties properties)
{
String firstName = null;
String lastName = null;
String fullName = null;
firstName = properties.AfterProperties["FirstName"].ToString();
lastName = properties.AfterProperties["Title"].ToString();
fullName = properties.AfterProperties["FullName"].ToString();
fullName = ComputeFullName(firstName, lastName, fullName);
properties.AfterProperties["FullName"] = fullName;
}
public override void ItemUpdating(SPItemEventProperties properties)
{
String firstName = null;
String lastName = null;
String fullName = null;
firstName = properties.AfterProperties["FirstName"].ToString();
lastName = properties.AfterProperties["Title"].ToString();
fullName = properties.AfterProperties["FullName"].ToString();
fullName = ComputeFullName(firstName, lastName, fullName);
properties.AfterProperties["FullName"] = fullName;
}
public String ComputeFullName(String firstName,
String lastName,
String fullName)
{
if (String.IsNullOrEmpty(fullName))
return String.Format("{0}, {1}", lastName, firstName);
else
return fullName;
}
}
}
Voilà, notre EventHandler est maintenant complet. Il nous faut maintenant le déployer.
Afin de connaître le nom des colonnes disponibles sur la liste, vous trouverez dans le code en exemple une méthode TraceColumnName qui vous permet de lister les colonnes de la liste sur laquelle travaille le handler. En voici le code
public void TraceColumnName(ref SPItemEventProperties properties)
{
foreach (Object o in properties.AfterProperties)
{
properties.ErrorMessage += String.Format("{0} - {1}\n",
((System.Collections.DictionaryEntry)o).Key.ToString(),
((System.Collections.DictionaryEntry)o).Value.ToString());
}
properties.Cancel = true;
}
Que fait donc cette méthode ?
C’est simple, elle affiche la liste des colonnes disponibles avec leur valeur à partir de la collection AfterProperties et annule l’évènement en simulant une erreur. Le message d’erreur alors affiché correspond aux colonnes avec leur valeur. Pour utiliser cette méthode, modifiez l’évènement ItemAdding comme suit :
public override void ItemAdding(SPItemEventProperties properties)
{
TraceColumnName(ref properties);
return;
String firstName = null;
String lastName = null;
String fullName = null;
firstName = properties.AfterProperties["FirstName"].ToString();
lastName = properties.AfterProperties["Title"].ToString();
fullName = properties.AfterProperties["FullName"].ToString();
fullName = ComputeFullName(firstName, lastName, fullName);
properties.AfterProperties["FullName"] = fullName;
}
Que se passe-t-il alors ?
Lors de l’ajout d’un contact dans notre liste, la méthode TraceColumnName sera appelée. Cette dernière annulera l’insertion et retournera en message d’erreur une liste sous la forme nomDeLaColonne – valeurDeLaColonne.
Quand vous n’en avez plus besoin, il vous suffit de supprimer ou de commenter le code rajouté.
Pour déployer notre EventHandler, nous allons utiliser une des autres nouveautés de WSS 3.0 : les features. Cette nouveauté permet de venir enrichir un site WSS avec de nouvelles fonctionnalités. Un prochain article sera dédié aux features. Nous allons pour le moment nous contenter de voir comment créer la feature permettant de déployer notre EventHandler dans note site WSS.
La feature permettant de déployer notre EventHandler se compose de 2 fichiers XML. Avant d’aller plus en avant, revenons dans notre projet et créons un dossier « FullNameContactFeature ». Ce répertoire contiendra les 2 fichiers xml qui composent notre feature.
Créons maintenant notre premier fichier xml et nommons-le « feature.xml » (attention, le nom est imposé). Ce premier fichier va nous permettre d’informer WSS qu’une nouvelle feature est disponible et de fournir à WSS les informations pour la charger.
Ce premier fichier est très simple (cf. code ci-dessous) :
feature.xml
<Feature
Scope="Web"
Title="Handler to standard contact list : compute full name"
Id="E854E03E-BCDD-4a88-8C20-902BC21FBFB2"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="Elements.xml"/>
</ElementManifests>
</Feature>
· L’attribut Scope permet de spécifier la portée de notre feature (Farm, Web, …)
· L’attribut Title contient le titre de notre feature tel qu’il sera affiché dans la collection des features du site
· L’attribut Id correspond à un Guid qui va identifier votre feature de manière unique. Pour remplir cette valeur, générez à l’aide de Visual Studio 2005 un nouveau Guid (menu Tools / Create GUID), copiez le Guid généré et collez la valeur à l’attribut Id.
· L’attribut Location de la section ElementManifest permet de communiquer à WSS le nom du fichier dans lequel il va pouvoir trouver les informations détaillées de la feature. Dans mon Exemple, ce fichier se nomme Elements.xml
Créons maintenant le second fichier .xml. Nous le nommerons donc Elements.xml. Ce fichier va donc décrire le type de feature, l’assembly contenant le code correspondant, …. Voici le contenu de notre fichier :
Elements.xml
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Receivers ListTemplateId="105">
<Receiver>
<Name>Full Name Handler for default contact on updating</Name>
<Type>ItemUpdating</Type>
<SequenceNumber>30001</SequenceNumber>
<Assembly>Bewise.Wss3.Sample.EventHandler, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=995401eda3d8bd0c</Assembly>
<Class>Bewise.Wss3.Sample.EventHandler.FullNameContactHandler</Class>
</Receiver>
<Receiver>
<Name>Full Name Handler for default contact on add</Name>
<Type>ItemAdding</Type>
<SequenceNumber>30002</SequenceNumber>
<Assembly>Bewise.Wss3.Sample.EventHandler, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=995401eda3d8bd0c</Assembly>
<Class>Bewise.Wss3.Sample.EventHandler.FullNameContactHandler</Class>
</Receiver>
</Receivers>
</Elements>
· L’attribut ListTemplateId de la section Receivers correspond à la valeur du type de liste sur laquelle va porter l’EventHandler. Dans WSS, les listes de contacts ont l’Id 105
· La section Receivers va ensuite contenir autant de section Receiver que d’évènement écouté. Dans notre exemple, notre handler réagit sur 2 évènements : l’ajout et la mise à jour. Nous allons donc créer 2 sections Receiver.
· Pour chacune des sections Receiver,
o l’attribut Name décrit l’action du handler sur l’évènement (enfin, vous y mettez ce que vous voulez !)
o l’attribut Type nomme l’évènement sur lequel doit réagir le handler. Dans notre exemple, le premier est ItemUpdating et le second ItemAdding (ou vice et versa)
o L’attribut SequenceNumber correspond à un numéro d’ordre unique pour les évènements.
o L’attribut Assembly donne le nom complet de l’assembly contenant le code du handler à exécuter
o L’attribut Class donne le nom de la classe qui hérite de SPItemEventReceiver
Pour plus d’informations sur les autres possibilités offertes pour configurer le déploiement du handler via les features, allez voir le site de Microsoft http://msdn2.microsoft.com/en-us/library/ms431081.aspx
Pour finir notre feature, assurez-vous dans les propriétés des 2 fichiers xml qu’ils seront bien copiés dans le répertoire output. Compilez votre projet en release. Vous devriez tous obtenir :
· Une assembly Bewise.Wss3.Sample.EventHandler.dll
· Un répertoire FullNameContactFeature contenant
o Un fichier feature.xml
o Un fichier elements.xml
Copiez l’assembly dans le répertoire FullNameContactFeature et voilà, notre feature est prête à être déployée.
Notre feature est prête, reste plus qu’à la déployer dans WSS. Pour ce faire, copions le répertoire FullNameContactFeature créé ci-dessus dans le répertoire FEATURE de WSS. Dans une installation par défaut, ce répertoire se trouve ici : C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES
Nous devons donc obtenir :

Ensuite, il nous faut ajouter notre assemby dans le GAC. Pour cela, « drag and dropper » l’assembly Bewise.Wss3.Sample.EventHandler.dll dans le répertoire C:\WINDOWS\assembly de manière à obtenir ceci :

Enfin, passons à la dernière étape pour que notre feature apparaisse dans notre site WSS. Ouvrez la console et déplacez-vous dans le répertoire bin de WSS (par défaut dans C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN) et exécutez la commande suivante :
Stsadm.exe -o installfeature -filename FullNameContactFeature\feature.xml -force
· Le paramètre -filename correspond au chemin relatif d’accès à notre fichier feature.xml depuis le répertoire FEATURE de WSS.
· Le paramètre –force permet de forcer le redéploiement de la feature (notamment dans le cas d’une mise à jour)
Si la commande réussit, le message « Operation completed successfully » doit apparaître. Exécutez ensuite la commande IISRESET pour forcer un redémarrage du site WSS.
La liste des features disponibles avant la commande STSADM :
La liste des features disponibles après la commande STSADM :
Il ne nous reste plus qu’à activer notre feature en cliquant sur Activate puis à tester que tout fonctionne correctement. Pour cela, créez une nouvelle liste de contacts. Ajoutez un nouveau contact en remplissant uniquement le First Name et le Last Name puis validez. Editez à nouveau le contact : la colonne Full Name est bien remplie avec la concaténation des 2 valeurs précédentes.
Les EventHandlers offrent la possibilité d’ajouter facilement des règles de gestion sur toutes les listes de WSS 3.0 moyennant un peu de développement. A vous de jouer maintenant.