Julien Bakmezdjian

Consultant technologies de développement Microsoft

Objectif : Réaliser un workflow « state-machine » pour SharePoint

L’objectif de ce tutorial est de créer un workflow « machine à états » pour Windows SharePoint Services, avec Visual Studio 2005. Le workflow en question permettra d’établir un process RH pour les mouvements internes. Le process reste ici très simpliste : le workflow sera constitué de 2 étapes principales : à l’étape 1, la RH décide de l’action à prendre vis-à-vis d’une candidature : on peut accepter ou refuser une candidature. On peut également demander au candidat de (re)passer un nouvel entretien. L’étape correspond à cet entretien est l’état n°2 : lorsque le candidat a passé son entretien, il l’indique au workflow qui revient alors à l’étape 1.

 

Pré-requis :

·         Niveau : Confirmé

·         Expérience avec Visual C#/.NET nécessaire

·         Expérience de SharePoint et des workflow

·         Microsoft Visual Studio 2005

Le workflow

1.       Dans Visual Studio 2005 (où les extensions pour SharePoint ont été installées), créer un nouveau projet de type « SharePoint Server State Machine Workflow Library » :


2.       Depuis les propriétés du projet créé, ajouter une signature :


3.       Compiler le projet. Si une erreur survient, éditer le fichier « Workflow1.cs » et supprimer la ligne suivante :


4.       Déplacer la DLL résultante dans le GAC. Cela nous permet de récupérer le PulicKeyToken de l’assembly. Nous en aurons besoin plus tard. Supprimer ensuite la DLL du GAC :


5.       Ouvrir « Workflow1.cs » en mode design :


6.       Ajouter 3 états afin d’obtenir :


7.       Cliquer-droit sur l’état n°3 et sélectionner « Set as Completed State » :


8.       Glisser une activité StateInitialization dans l’état n°1 :


9.       Glisser une activité EventDriven


10.       Réaliser les mêmes étapes 8 et 9 avec l’état n°2 :


11.       Dans l’état n°1, double-cliquer sur stateInitializationActivity1 :


12.       Ajouter une activité SendEmail (note : si les activités « SharePoint » ne sont pas disponibles dans la boîte à outils, cliquer-droit sur la boîte à outils, sélectionner « Select Items », puis, dans l’onglet « Activities », cliquer sur le bouton « Browse ». Pointer alors « C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI\microsoft.sharepoint.WorkflowActions.dll » et valider la boîte de dialogue) :


13.       Positionner le CorrelationToken à workflowToken (ceci est important pour l’activité SendEmail fonctionne convenablement) :


14.       Pour chaque propriété Subject, To et Body (et éventuellement CC et BCC), créer un nouveau membre auquel lier la propriété :


15.       Basculer en vue événements pour l’activité « email » :


16.       Doublez-cliquer sur MethodInvoking. Cela va créer un gestionnaire d’événements dans lequel on ajoute ce code :
            sendEmail1_Body1 = "Bonjour, vous devez traiter cette demande";
            sendEmail1_Subject1 = "Demande de mouvement interne";
            sendEmail1_To1 = "rh@societe.com";

17.       Si votre système d’emails n’est pas configuré correctement, vous pouvez désactiver cette activité en positionnant sa propriété Enabled à false :


                            

18.       De retour en mode design, ajouter une activité LogToHistoryListActivity :


19.   Lier la propriété HistoryDescription à un nouveau membre de classe :


20.   Dans le gestionnaire d’événements MethodInvoking, ajouter ce code :
            logToHistoryListActivity1_HistoryDescription1 = "L'état 1 a été activé";

21.   De retour en mode design, ajouter une activité de type CreateTask :



Positionner son CorrelationToken comme suit :


22.   Lier les propriétés TaskId et TaskProperties à des nouveaux membres de classe.

23.       Lier la propriété ListItemId à la propriété TaskItemId du membre créé à l’étape 22 ci-dessus pour la propriété TaskProperties :


24.       Depuis le gestionnaire d’événement MethodInvoking, ajouter ce code (note : dans le cas de l’activité CreateTask de l’état n°2 -voir étape 26 ci-dessous- on peut supprimer la deuxième ligne nextStep = 0 ; nous verrons à l’étape 30 l’utilisation de cette variable nextStep) :
            createTask1_TaskId1 = Guid.NewGuid();

            createTask1_TaskProperties1 = new SPWorkflowTaskProperties();
            createTask1_TaskProperties1.Title = "Mouvement interne";
            createTask1_TaskProperties1.Description = "Prendre une décision sur ce dossier";
            createTask1_TaskProperties1.AssignedTo = "societe\\rh";


            nextStep = 0 ;

25.       Revenir en mode design, et cliquer sur « Workflow1 » dans le fil d’Ariane pour revenir à une vue générale du workflow :


26.       Réaliser les étapes 11 à 24 sur l’état n°2. Changer les messages des emails et des logs, ainsi que le destinataire des emails.

27.       Double-cliquer sur l’activité EventDriven de l’état n°1. Ajouter une activité OnTaskChanged :


28.       Positionner son CorrelationToken à « RHTask » :


29.       Lier la propriété TaskId au membre déjà existant createTask1_TaskId1 :


30.       Dans le gestionnaire d’événement Invoked, utiliser le code suivant (ce code nécessite la déclaration d’une variable nextStep de type int au niveau de la classe du workflow) :
            SPListItem task = workflowProperties.TaskList.GetItemById(createTask1_TaskProperties1.TaskItemId);
            if (task["Decision"] .ToString().ToLower()  == "rdv")
                nextStep = 1; // Demande d’un nouvel entretien
            if (task["Decision"] .ToString().ToLower()  == "refuse")
                nextStep = 2; // Refuse
            if (task["Decision"] .ToString().ToLower()  == "accepte")
                nextStep = 3; // Accepte

31.       En mode design, ajouter trois activités IfElse imbriquées comme suit :


32.   Pour positionner la condition de la première branche, afficher les propriétés de l’activité, choisir « Declarative Rule Condition » comme type de condition, puis dans « ConditionName » cliquer sur « ... ».  Une fenêtre permettant de définir des règles conditionnelles apparaît. Cliquer sur « New » pour ajouter une règle, et y inscrire :
                               nextStep == 1

33.   Le résultat ressemble à :


34.   Faire de même avec la seconde activité IfElse, avec cette condition :
                               nextStep == 2

35.   De même avec la troisième activité IfElse et cette condition :
                               nextStep == 3

36.   Nous avons donc maintenant 4 chemins différents auxquels il faut ajouter des instructions.

37.   Dans la première branche, on ajoute simplement une activité SetState que l’on dirige vers l’état n°2.

38.   Dans la seconde branche, on ajoute une activité SendEmail pour annoncer le refus (optionnel dans le cadre de cette démonstration), et une activité de logging. On dirige ensuite vers l’état final avec une activité SetState :


Dans la troisième branche, on ajoute une activité SendEmail  pour annoncer l’acceptation (optionnel dans le cadre de cette démonstration), et une activité de logging. On dirige

39.       ensuite vers l’état final avec une activité SetState :


40.       Enfin, dans la dernière branche (pas de décision prise), on ne fait rien.

41.       Le résultat final ressemble à :


42.       Revenir à la vue général du workflow, puis double-cliquer sur l’activité EventDriven de l’état n°2.

43.       Ajouter une activité OnTaskChanged et positionner ses propriétés CorrelationToken et TaskId convenablement :


44.       Dans le gestionnaire Invoked, ajouter ce code (qui nécessite l’ajout d’une déclaration de la variable rdv de type bool ) :
            SPListItem task = workflowProperties.TaskList.GetItemById(createTask2_TaskProperties1.TaskItemId);
            rdv = (bool)task["RDV"];

45.       Ajouter une activité IfElse :


46.       Pour la condition de la branche If, on ajoute une condition sur rdv :


47.       Dans la branche de gauche, on redirige vers l’état n°1 (après logging éventuel).

48.   Dans la branche de droite, on ne fait rien.

49.   Depuis l’état InitialState et son activité EventDriven, ajouter une activité SetState vers l’état n°1.

50.   Le résultat final ressemble à :


Déploiement et test

51.   Nous allons ici déployer notre workflow, puis créer les listes dont il « a besoin » pour fonctionner. Les manipulations ne sont pas forcément celles recommandées (nous devrions plutôt utiliser des content types) mais elles vont nous permettre de tester rapidement notre workflow. Attention aux noms des listes et des colonnes (et notamment à la casse), puisque nous avons codé en dur leurs noms dans le code source du workflow.

52.   Ouvrir Feature.xml. Cliquer-droit et ajouter le snippet « Feature » (si le snippet n'est pas présent dans Visual Studio, aller dans le Code Snippet Manager, passer en langage XML, et importer les fichiers de C:\Program Files\Microsoft Visual Studio 8\Xml\1033\Snippets\SharePoint Server Workflow). Modifier le code comme suit (ne pas oublier d’enlever les lignes relatives au « Feature Event Receiver »):


53.   Ouvrir Workflow.xml. Cliquer-droit et ajouter le snippet « Workflow ». Modifier le code comme suit :


54.   Editer les propriétés du projet comme suit :


55.   Compiler le projet.

56.       Créer une liste « Candidatures » (avec les colonnes de son choix) et y associer le nouveau workflow :


57.       Créer les colonnes « RDV » et « Decision » au niveau du content type « Task ». Cette manipulation n’est pas très « propre » puisque nous modifions un content type par défaut, alors qu’il vaudrait mieux en créer un nouveau, spécifique à notre workflow. Cependant, cela va nous permettre de tester rapidement notre workflow.
Note : le nom des colonnes est « case-sensitive ».
Pour modifier ce content type :

a.       Depuis les « Site Settings », choisir « Site content types ».

b.      Si on ne se trouve pas sur le site racine de la collection de sites, cliquer sur le parent du content type « Team site » :


c.       Sélectionner le content type « Task » :


d.      Cliquer sur « Add from new site column » pour ajouter la colonne « RDV » (de type « Yes/ No », avec une valeur par défaut à « No » ) :


e.      Cliquer sur « Add from new site column » pour ajouter la colonne « Decision » (de type « Choice », avec les valeurs « n/a », « rdv », « refuse » et « accepte ») :


58.       Depuis la liste « Candidatures », créer un nouvel élément, et manipuler/observer le workflow.