Team System : synchroniser les liens sur les documents SharePoint

15 avril 2009 10:05 par Didier Godat

Les éléments de travail (work items) peuvent être liés à différents objets ; il est, par exemple, intéressant de lier certains éléments à des documents stockés dans le portail Sharepoint associé à notre projet d’équipe (spécification, plan de test, etc.). Il y a néanmoins un petit inconvénient à ce type de lien car il est statique. Or dans le cas de liaisons avec une bibliothèque de documents Sharepoint, si l’on a mis en place le versioning des documents, il serait préférable de maintenir le lien sur le document d’origine et non sur la dernière version de celui-ci. En effet, l’évolution du contenu du document (cas d’une spécification) est susceptible de ne plus être en phase avec l’élément de travail tel qu’il est défini.

Pour résoudre ce point, nous pouvons nous appuyer sur les APIs de WSS 3.0 et de Team System 2008 pour mettre en place une synchronisation automatique des liens lorsqu’un document est amené à évoluer. Dans notre exemple, toute modification entraîne la synchronisation mais rien ne vous empêche d’être plus restrictif et de n’intégrer ce mécanisme que pour des révisions majeures des documents.

Afin de mettre automatiquement à jour les liens dans les éléments de travail, nous allons utiliser les événements de SharePoint (Event Handler). Il est possible de créer des gestionnaires d’événements sur tous les types de listes de WSS. Dans notre cas, nous allons surtout nous intéresser à l’événement ‘ItemCheckedIn’ qui est appelé après la mise à jour (check-in) d’un élément. Pour écrire son propre ‘Event Handler’, il y a quelque points à respecter. Premièrement, il faut signer le projet car l’Event Handler doit être déployé dans le GAC, ensuite il faut ajouter comme référence l’assembly Microsoft.SharePoint (qui se trouve dans le répertoire ISAPI du répertoire 12 de WSS), puis créer une classe qui hérite de la classe ‘SPItemEventReceiver’. A partir de là, on peut surcharger plusieurs événements ; nous allons nous intéresser uniquement à l’événement ‘ItemCheckedIn’. Dans la méthode ‘ItemCheckedIn’ de l’Event Handler nous allons récupérer l’url courante du document ainsi que l’url de la version précédente (si elle existe). Si la gestion de version n’est pas active sur la liste courante, l’url du document reste toujours la même quelque soit les modifications apportés. En cas de nouvelle version, nous allons mettre à jour l’ensemble des éléments de travail de Team System contenant une référence vers le document en question.

   1: #region Imports
   2: using System;
   3: using Microsoft.SharePoint;
   4: #endregion
   5:  
   6: namespace Tekigo.WSS.Update
   7: {
   8:   /// <summary>
   9:   /// 
  10:   /// </summary>
  11:   public class Listener : SPItemEventReceiver
  12:   {
  13:     #region ItemCheckIn
  14:     /// <summary>
  15:     /// Méthode appelée après le check-in d'un document
  16:     /// </summary>
  17:     /// <param name="pProperties">Les propriétés</param>
  18:     public override void ItemCheckedIn(SPItemEventProperties pProperties)
  19:     {
  20:       string url = String.Concat(pProperties.ListItem.Web.Url, "/", pProperties.ListItem.Versions[0].Url);
  21:       string urlOldVersion = String.Empty;
  22:  
  23:       if (pProperties.ListItem.Versions.Count > 1)
  24:       {
  25:         urlOldVersion = String.Concat(pProperties.ListItem.Web.Url, "/", pProperties.ListItem.Versions[1].Url);
  26:       }
  27:     }
  28:     #endregion
  29:   }
  30: }

La deuxième partie du programme consiste donc à mettre à jour les éléments de travail de Team System. Pour utiliser les API de Team System, nous allons inclure les références ‘Microsoft.TeamFoundation.Client’ et ‘Microsoft.TeamFoundation.WorkItemTracking.Client’. Nous allons récupérer le magasin contenant l’ensemble des work items mais, dans un souci de performance, nous n’allons pas parcourir l’ensemble de tous les work items, mais utiliser une requête ne récupérant que ceux ayant au moins un lien vers un document. Il suffit alors de parcourir l’ensemble des hyperliens des work items et de vérifier si l’url correspond à l’url du document en cours de modification ; si tel est le cas, il faut mettre à jour l’adresse afin qu’elle pointe sur celle de l’ancienne version. Il existe cependant un léger problème car il n’est pas possible de faire une mise à jour directe des adresses des hyperliens, car elles sont considérées comme des clefs. Il faut donc d’abord ajouter un nouvel hyperlien contenant les informations de la nouvelle url puis supprimer l’ancien hyperlien. Cette action est la plus sensible car si un problème survient au cours de la suppression, il y aura deux hyperliens,  un sur l’ancienne version du document et un autre sur la nouvelle version. Pour informer que le lien a été modifié automatiquement, on rajoute une information dans le commentaire de l’hyperlien.

   1: /// <summary>
   2:  /// Méthode permettant de mettre à jour les url dans les workitems
   3:  /// </summary>
   4:  /// <param name="pUrl">Url à modifier</param>
   5:  /// <param name="pNewUrl">Url correspondant à l'ancienne version du document</param>
   6:  private void UpdateTeamSystem(string pUrl, string pNewUrl)
   7:  {
   8:    TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(TFS_SERVER);
   9:    WorkItemStore store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
  10:  
  11:    foreach (WorkItem workItem in store.Query("SELECT [System.Id], [System.Title] FROM WorkItems WHERE [System.HyperLinkCount] > 0 "))
  12:    {
  13:      if (workItem.Links != null && workItem.Links.Count > 0)
  14:      {
  15:        int length = workItem.Links.Count;
  16:        Link link = null;
  17:  
  18:        Hyperlink hyperlink = null;
  19:  
  20:        for (int i = 0; i < length; i++)
  21:        {
  22:          link = workItem.Links[i];
  23:  
  24:          if (link.BaseType == BaseLinkType.Hyperlink && HttpUtility.HtmlDecode(((Hyperlink)link).Location) == pUrl)
  25:          {
  26:            hyperlink = new Hyperlink(pNewUrl);
  27:            if (!String.IsNullOrEmpty(link.Comment))
  28:            {
  29:              hyperlink.Comment = String.Concat("[Modification automatique de l'url] - ", link.Comment);
  30:            }
  31:            else
  32:            {
  33:              hyperlink.Comment = "[Modification automatique de l'url]";
  34:            }
  35:  
  36:            workItem.Links.Add(hyperlink);
  37:            workItem.Links.RemoveAt(i);
  38:            workItem.Save();
  39:          }
  40:        }
  41:      }
  42:    }
  43:  }

 

Maintenant il ne nous reste plus qu’à installer (disons plutôt enregistrer) l’EventHandler dans SharePoint. La première étape consiste à placer la DLL dans le GAC. Le plus simple est de faire un fichier BAT utilisant l’exécutable ‘gacutil’ et d’appeler ce fichier après la compilation du projet.

Img 

Une fois la DLL enregistrée dans le GAC, il faut associer l’EventHandler à une liste ; pour cela, il y a deux possibilités, soit en faisant du code

   1: SPSite Site = new SPSite("Url Du Site");
   2: SPWeb Web = Site.OpenWeb();
   3: Web.Lists["La Liste Cible"].EventReceivers.Add(SPEventReceiverType.<Type d'évènement>,Signature de l'assembly, Nom de la classe);

Soit en utilisant un outil tiers comme celui proposé à cette adresse : Event Handler Explorer

L’installation est presque terminée, il ne reste plus qu’a résoudre un problème de droit. En effet, étant donné que c’est le processus WSS qui va faire une modification dans Team System, il faut donner les droits d’écriture au processus WSS sur le répertoire ‘C:\Documents and Settings\[Utilisateur]\ Local Settings\Application Data\Microsoft\Team Foundation\2.0\Cache’.

Si vous souhaitez recevoir la solution Visual Studio complète, contactez-nous via notre page contact.