I. Introduction▲
Un workflow est une séquence d'actions qui suivent un processus business défini par une entreprise et qui intervient à un instant T. Le concept de workflow a été introduit par Microsoft dans la "version" 3 du framework.
Avant tout développement de workflow avec Visual Studio, il faut se poser la question de savoir si ce que l'on veut faire est faisable avec Sharepoint Designer. Si tel est le cas, il faut privilégier cette piste car elle est beaucoup plus rapide et le risque d'induction de bug est réduit voire nul.
Dans ce tutoriel, nous allons créer un workflow qui crée une annonce dans la liste "Announcements" d'un site enfant lorsqu'un document est ajouté à une liste du "Top Level Site". Cet exemple est simpliste mais permet de comprendre la mise en oeuvre d'un workflow. Par ailleurs cet exercice n'est pas faisable avec un workflow développé via Sharepoint Designer car celui-ci ne permet pas de mettre à jour une liste d'un site différent de la liste sur laquelle le workflow s'applique.
II. Développement▲
II-A. Outils▲
Pour réaliser cet exercice, il est indispensable d'installer les templates Visual Studio 2005 que vous trouverez ici
II-B. Création du projet▲
Lorsque vous avez installé les templates, ouvrez Visual Studio et créez un nouveau projet de type "Sequential Workflow" comme illustré par l'image ci-dessous.
Ceci fait, dans l'explorateur de solution, vous retrouverez tous les fichiers créés automatiquement par le template.
II-C. Le fichier feature.xml▲
Le fichier feature.xml sert à décrire la nature de la fonctionnalité de votre workflow et permet également de spécifier une portée. Lorsque le workflow sera déployé sur Sharepoint en tant que feature, vous pourrez l'activer/la désactiver à souhait (voir section III). Lorsque vous double-cliquez sur ce fichier dans l'explorateur de solution. Vous découvrirez des instructions expliquant comment insérer le squelette XML de la feature.
Après avoir exécuté les instructions, vous devriez obtenir ceci
<Feature Id="GUID"
Title="Default Title"
Description="This feature is a workflow that ..."
Version="12.0.0.0"
Scope="Site"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="workflow.xml" />
</ElementManifests>
<Properties>
<Property Key="GloballyAvailable" Value="true" />
</Properties>
</Feature>
Voici l'explication de chaque élément
- Id : vous devez insérer un GUID (identifiant unique), ceci est expliqué dans la section suivante
- Title : simplement le titre de votre feature
- Description: la description de votre feature, elle apparaîtra telle quelle aux administrateurs Sharepoint
- Version: une version
- Scope: définit la portée de la feature. Farm = ferme sharepoint, Site = Collection de site, Web=uniquement un site
- xmlns: espace de noms
- ElementManifest Location : spécifie l'emplacement du fichier workflow.xml (expliqué plus bas)
- GloballyAvailable: détermine la disponibilité
II-C-1. Attribution du GUID▲
Pour créer un GUID, rien de plus simple. Positionnez votre curseur sur le mot "GUID" de la ligne Id="GUID". Ensuite, cliquez sur "Tools->Create GUID" pour obtenir cette fenêtre
Cliquez sur "Copy" puis sur "Exit". Collez le contenu pour remplacer "GUID" et retirez les accolades entourant le GUID. Vous devriez obtenir une suite de ce style {D42A70AB-BAA6-4d68-BBCA-1469A3EBD8F6}, après avoir retiré les accolades : D42A70AB-BAA6-4d68-BBCA-1469A3EBD8F6
Vous n'avez plus qu'à définir le scope (portée) qui est par défaut "Site" c'est à dire, toute la collection de sites.
Voici notre fichier feature.xml de l'exemple après transformation
<Feature Id="36D935D9-2BE5-4e98-A8B9-FD72B1A730B2"
Title="Workflow Annonce"
Description="Ce workflow crée une annonce lorsqu'un document est ajouté dans la liste 'Shared Documents'"
Version="12.0.0.0"
Scope="Site"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="workflow.xml" />
</ElementManifests>
<Properties>
<Property Key="GloballyAvailable" Value="true" />
</Properties>
</Feature>
II-D. Le fichier workflow.xml▲
Le fichier workflow.xml sert à identifier votre workflow de manière unique via un GUID, et sert à associer le workflow déployé à votre assemblage. Il permet également d'associer des formulaires Infopath.
Comme pour le fichier feature.xml, suivez les instructions de Visual Studio pour insérer le squelette XML. Vous devriez obtenir ceci
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Workflow
Name="My Workflow"
Description="This workflow ..."
Id="GUID"
CodeBesideClass="ProjectName.Workflow1"
CodeBesideAssembly="ProjectName, Version=3.0.0.0, Culture=neutral, PublicKeyToken=publicKeyToken"
TaskListContentTypeId="0x000"
AssociationUrl="_layouts/MyAssocForm.aspx"
InstantiationUrl="_layouts/MyInitForm.aspx"
ModificationUrl="_layouts/MyModForm.aspx">
<Categories/>
<MetaData>
<Modification_GUID_Name>Name of Modification</Modification_GUID_Name>
<StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
</MetaData>
</Workflow>
</Elements>
Voici l'explication de chaque élément
- Name: le nom de votre workflow
- Description: la description de votre workflow (apparaît lors de l'association du workflow à une liste)
- Id: GUID même chose que pour la feature
- CodeBesideClass: le nom de votre projet suivi du nom de votre classe principale.
- CodeBesideAssembly: la signature de votre assemblage. (voir section II-E)
- TaskListContentTypeId: la liste des tâches liée (nous ne l'utiliserons pas dans cet exemple)
- AssociationUrl, InstanciationUrl et ModificationUrl : pages aspx pour les workflows interactifs (nous ne l'utiliserons pas dans cet exemple)
Voici notre fichier workflow.xml de l'exemple après transformation
<?xml version="1.0" encoding="utf-8" ?>
<!-- _lcid="1033" _version="12.0.3015" _dal="1" -->
<!-- _LocalBinding -->
<!-- Insert Workflow.xml Code Snippet here. To do this:
1) Right click on this page and select "Insert Snippet" (or press Ctrl+K, then X)
2) Select Snippets->Windows SharePoint Services Workflow->Workflow.xml Code -->
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Workflow
Name="Workflow Annonce"
Description="Ce workflow crée une annonce lorsqu'un document est ajouté dans la liste 'Shared Documents'"
Id="6FEFAB53-7CF7-49e5-9815-BED1AAA2B2A6"
CodeBesideClass="AnnouncementWorkflow.Workflow1"
CodeBesideAssembly="AnnouncementWorkflow, Version=3.0.0.0, Culture=neutral, PublicKeyToken=cc22401ad6f86bc6"
>
<Categories/>
</Workflow>
</Elements>
Vous devez également attribuer un GUID à l'attribut Id comme expliqué pour le fichier feature.xml.
Note: tant pour le fichier workflow.xml que pour le fichier feature.xml, Visual Studio a automatiquement lié le schéma XSL C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\XML\wss.xsd afin de proposer l'intellisence. Il est intéressant de connaître l'emplacement de ce fichier XSD car il est parfois nécessaire de faire le lien manuellement.
II-E. Le fichier Install.bat▲
Le fichier Install.bat automatiquement créé par le template Visual Studio sert à déployer la feature et le workflow automatiquement dans Sharepoint. Il faudra donc demander à Visual Studio de l'exécuter lors du build. Lorsque vous cliquez sur le fichier bat dans l'explorateur de solution, vous obtenez ceci. J'ai placé mes commentaires en remarque dans le fichier directement après le mot clé REM
:: Before running this file, sign the assembly in Project properties
::
:: To customize this file, find and replace
:: a) "MyFeature" with your own feature names
:: b) "feature.xml" with the name of your feature.xml file
:: c) "workflow.xml" with the name of your workflow.xml file
:: d) "http://localhost" with the name of the site you wish to publish to
echo Copying the feature...
rd /s /q "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MyFeature"
REM: suppression du répertoire contenant les fichiers déployés avec la feature
mkdir "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MyFeature"
REM: Création du répertoire contenant les fichiers déployés avec la feature
copy /Y feature.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MyFeature\"
REM: copie du fichier feature.xml
copy /Y workflow.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MyFeature\"
REM: copie du fichier workflow.xml
xcopy /s /Y *.aspx "%programfiles%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"
REM: copie des fichiers .aspx liés
echo Adding assemblies to the GAC...
::"%programfiles% (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -uf MyFeature
REM: désinstallation de l'assemblage de la GAC (global assembly cache)
::"%programfiles% (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if bin\Debug\MyFeature.dll
REM: Installation de l'assemblage dans la GAC
echo Activating the feature...
pushd %programfiles%\common files\microsoft shared\web server extensions\12\bin
stsadm -o installfeature -filename MyFeature\feature.xml -force
REM: déploiement de la feature
stsadm -o activatefeature -filename MyFeature\feature.xml -url http://localhost
REM: activation de la feature
echo Doing an iisreset...
popd
iisreset
REM: redémarrage de IIS, vous pouvez aussi redémarrer uniquement le pool d'application
Vous devez suivre les instructions données par Visual Studio pour transformer le fichier bat selon vos besoins. Voici celui de notre exemple après transformation
:: Before running this file, sign the assembly in Project properties
::
:: To customize this file, find and replace
:: a) "MyFeature" with your own feature names
:: b) "feature.xml" with the name of your feature.xml file
:: c) "workflow.xml" with the name of your workflow.xml file
:: d) "http://localhost" with the name of the site you wish to publish to
echo Copying the feature...
rd /s /q "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\AnnouncementWorkflow"
mkdir "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\AnnouncementWorkflow"
copy /Y feature.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\AnnouncementWorkflow\"
copy /Y workflow.xml "%CommonProgramFiles%\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\AnnouncementWorkflow\"
xcopy /s /Y *.aspx "%programfiles%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS"
echo Adding assemblies to the GAC...
"%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -uf AnnouncementWorkflow
"%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if bin\Debug\AnnouncementWorkflow.dll
:: Note: 64-bit alternative to lines above; uncomment these to install on a 64-bit machine
::"%programfiles% (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -uf AnnouncementWorkflow
::"%programfiles% (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if bin\Debug\AnnouncementWorkflow.dll
echo Activating the feature...
pushd %programfiles%\common files\microsoft shared\web server extensions\12\bin
::Note: Uncomment these lines if you've modified your deployment xml files or IP forms
::stsadm -o deactivatefeature -filename AnnouncementWorkflow\feature.xml -url http://momix
::stsadm -o uninstallfeature -filename AnnouncementWorkflow\feature.xml
stsadm -o installfeature -filename AnnouncementWorkflow\feature.xml -force
stsadm -o activatefeature -filename AnnouncementWorkflow\feature.xml -url http://momix
echo Doing an iisreset...
popd
iisreset
II-E-1. Signature de l'assemblage▲
La première chose à faire pour pouvoir déployer son assemblage dans la GAC (global assembly cache) est de le signer. Pour cela, sélectionnez votre projet dans l'explorateur de solution de Visual Studio et cliquez sur "Properties", ensuite sur l'onglet "Signing". Vous devriez obtenir ceci
II-E-2. Automatiser l'exécution du fichier bat▲
Allez dans les propriétés de votre projet et remplissez le post-build event comme illustré ci-dessous.
Après cette opération, votre workflow sera automatiquement déployé vers votre serveur Sharepoint dès que vous compilerez votre projet.
II-F. Chargement des contrôles workflow de Sharepoint dans la barre d'outils▲
Afin de pouvoir développer des workflow spécifiques à Sharepoint, vous devez ajouter les contrôles prévus à cet effet dans la barre d'outils.
Cliquez sur la barre d'outils avec le bouton droit, choisissez "Add Tab" pour ajouter un nouvel onglet, nommez-le "WSS", ensuite, cliquez sur "Choose Items", vous devez obtenir la fenêtre suivante
Triez la liste sur la colonne "NameSpace" et localisez l'espace de nom "Microsoft.Sharepoint.WorkflowActions". Ensuite, sélectionnez toutes les entrées correspondantes. Votre barre d'outils devrait maintenant contenir tous les contrôles spécifiques
Vous êtes désormais prêts à développer un workflow pour Sharepoint.
II-G. Description sommaire des principaux types d'activité liés aux workflows▲
La liste ci-dessous n'est pas exhaustive mais reprend les principales activités que l'on peut utiliser pour réaliser un workflow.
Code Activity |
---|
Cette activité permet d'associer une procédure évènementielle. On l'utilisera pour toute tâche non spécifique et non prévue par un autre type d'activité |
IfElseActivity |
---|
Utilisée lorsque l'on veut conditionnellement exécuter certaines étapes d'un workflow. Les expressions sont évaluées de gauche à droite. Si l'une des expressions est évaluée à Vrai, elle s'exécutera et le processus passera à l'activité suivante. Si aucune condition n'est satisfaite et que la dernière branche n'a pas de condition, elle sera considérée comme la partie "Else" et sera dès lors exécutée |
WhileActivity |
---|
C'est simplement une bouche While "modélisée" |
SequenceActivity |
---|
C'est une séquence d'activités. Très pratique pour pallier au pseudo problème ci-dessus. |
SuspendActivity, TerminateActivity, InvokeWorkflowActivity |
---|
Permettent respectivement de suspendre, arrêter un workflow ou invoquer l'exécution d'un autre workflow. |
ThrowActivity |
---|
Similaire à un Throw en dotnet ou java |
ParallelActivity |
---|
Permet l'exécution parallèle simultanée de plusieurs activités. Tant que toutes les activités contenues dans une ParallelActivity ne sont pas terminées, le workflow reste dans la ParallelActivity. Ce serait le cas aussi avec une SequenceActivity sauf que la SequenceActivity impose un ordre séquentiel alors que la ParallelActivity n'en impose pas. Une ParallelActivity est intéressante à utiliser lorsque l'on a besoin de l'intervention de plusieurs acteurs pour pouvoir passer à l'activité suivante sans toutefois imposer quel tel acteur intervienne avant tel autre. Imaginons une approbation de document où 2 personnes doivent avoir lu et approuvé le document et que l'on ne souhaite pas imposer un ordre d'intervention. |
DelayActivity |
---|
Similaire à un Thread.Sleep(). Dans le contexte d'un workflow, une DelayActivity sera surtout utilisée pour configurer un TimeOut |
ListenActivity |
---|
Ressemble à la ParallelActivity sauf que dès que l'une des sous-activités a été réalisée, le workflow sort de la ListenActivity alors que dans une ParallelActivity, toutes les activités filles doivent être complètées |
ReplicatorActivity |
---|
Boucle jusqu'à ce qu'une condition soit remplie et peut contenir plusieurs activités filles. Peut exécuter celles-ci séquentiellement ou parallèlement |
EventDrivenActivity |
---|
S'exécute uniquement lorsqu'un évènement précis se produit |
II-H. Description des principales activités liées à Sharepoint▲
Voici une liste non exhaustive des principales activités directement liées aux workflows destinés à Sharepoint
OnWorkflowActivated |
---|
Cette activité est automatiquement créée lorsque l'on crée un workflow Sharepoint. Elle ne peut d'ailleurs pas être enlevée. Comme son nom l'indique, elle s'exécute dès que le workflow a été démarré. |
OnWorkflowItemChanged |
---|
Cette activité est s'exécute lorsqu'un élément d'une liste est modifié |
OnWorkflowItemDeleted |
---|
Cette activité est s'exécute lorsqu'un élément d'une liste est supprimé. |
SetStateActivity |
---|
Permet de cibler la prochaine activité. C'est similaire à un GoTo. Par contre, elle ne permet que de pointer vers une activité de type System.Int32 (SateActivity par ex) |
OnTaskCreated, OnTaskChanged et OnTaskDeleted |
---|
S'exécutent respectivement lorsqu'une tâche associée au workflow est créée, modifiée ou supprimée. |
CreateTask, UpdateTask, DeleteTask et CompleteTask |
---|
Les workflows dans Sharepoint assignent souvent des tâches aux différents acteurs. CreateTask, UpdateTask et DeleteTask permettent comme leur nom l'indique de créer/modifier/supprimer une tâche. CompleteTask permet de marquer une tâche comme étant complétée, c'est à dire "terminée". |
RollbackTask |
---|
Permet de réinitialiser une tâche qui était préalablement complètée. |
OnWorkflowModified |
---|
S'exécute lorsqu'un utilisateur soumet un formulaire (infopath par ex) intervenant dans le workflow |
SendEmail |
---|
Durant le processus d'un workflow, les différents acteurs sont régulièrement notifiés par e-mail de l'avancement de celui-ci. Cette tâche facilite l'envoi d'email. |
LogToHistoryListActivity |
---|
Permet d'afficher un message dans l'historique d'exécution d'un workflow visible directement dans Sharepoint |
II-I. Contrôles de workflow intervenant dans notre exemple▲
Notre workflow est simplissime et tiens plus d'un "proof of concept" qu'autre chose mais voici néanmoins les différentes choses auxquelles il est judicieux de prêter attention.
- La tâche "OnWorkflowActivated" est automatiquement créée par le designer et est obligatoire. On peut lui associer du code mais ceci est facultatif
- La tâche "LogToHistoryListActivity", ici symbolisée par "History" va nous servir à créer un message qui apparaîtra dans l'historique du workflow
- La tâche "CreateAnnoncement" est une CodeActivity qui contient le code nécessaire pour créer l'annonce dans la liste Announcements
- Le Carré rouge contenant un cercle blanc symbolise la fin du workflow
Note: notre workflow est destiné à être utilisé lors de l'ajout d'un élément dans une liste documentaire, c'est pourquoi il n'écoute pas un évènement particulier comme OnWorkflowItemChanged ou OnWorkflowItemDeleted.
II-J. Le code▲
Je ne reprends ici que le code important, vous n'aurez qu'à télécharger l'exemple pour disposer du code complet.
Afin de ne pas coder en dur la liste cible ni le serveur Sharepoint, j'ai défini ces variables dans les settings du workflow comme illustré ci-dessous.
Propriété importante:
public
Microsoft.
SharePoint.
Workflow.
SPWorkflowActivationProperties workflowProperties =
new
Microsoft.
SharePoint.
Workflow.
SPWorkflowActivationProperties
(
);
Cette déclaration et instanciation automatiquement créées par le template de workflow représentent les propriétés de notre workflow. C'est par elles qu'il sera notamment possible de récupérer les valeurs de l'élément de liste ajouté/modifié/supprimé. wokflowProperties contient notamment les propriétés "BeforeProperties" et "AfterProperties" permettant de récupérer les anciennes et les nouvelles valeurs lors des mises à jour.
Voici le code lié à notre CodeActivity destiné à créer l'annonce dans la liste Announcements.
private
void
CreateAnnoncement_ExecuteCode
(
object
sender,
EventArgs e)
{
SPSite Site =
null
;
SPWeb Web =
null
;
SPList AnnouncementList =
null
;
SPListItem NewItem =
null
;
try
{
Site =
new
SPSite
(
AnnouncementWorkflow.
Properties.
Settings.
Default.
TargetSiteUrl);
//Ouverture d'un SPWeb, càd un site
Web =
Site.
OpenWeb
(
);
//0n pointe sur la liste d'annonces
AnnouncementList =
Web.
Lists[
AnnouncementWorkflow.
Properties.
Settings.
Default.
AnnouncementList];
//On instancie un nouvel élément (nouvelle ligne pour la liste)
NewItem =
AnnouncementList.
Items.
Add
(
);
//On crée un petit message
NewItem[
"Title"
]
=
"Le document "
+
workflowProperties.
Item[
"Title"
]
+
" a été mis en ligne"
;
//On crée un corps de message contenant l'URL du document
NewItem[
"Body"
]
=
"Vous pouvez consulter le document "
+
workflowProperties.
Item[
"Title"
]
+
" <a href='"
+
workflowProperties.
Item[
"EncodedAbsUrl"
]
+
"'>ici</a>"
;
//On met à jour l'élément de liste
NewItem.
Update
(
);
//On récupère l'ID
AnnouncementList.
Update
(
);
Web.
Update
(
);
//On met un message dans l'historique.
History.
HistoryDescription =
"Annonce "
+
NewItem.
ID.
ToString
(
) +
" créée avec succès"
;
}
catch
(
SPException Ex)
{
History.
HistoryDescription =
Ex.
Message;
}
finally
{
if
(
Web !=
null
) Web.
Close
(
);
if
(
Site !=
null
) Site.
Close
(
);
NewItem =
null
;
AnnouncementList =
null
;
Web =
null
;
Site =
null
;
}
}
Si vous disposez de plusieurs étapes dans votre workflow, il est indispensable de bien remettre à null les objets liés à la manipulation des éléments de listes sous peine de dysfonctionnements sérieux.
Note: Le système de workflow met à notre disposition des FaultHandlers pour gérer les exceptions, je ne les aborde pas dans ce tutoriel car ces composants mériteraient sans doute un tutoriel dédié. L'exemple fourni n'est donc pas optimal en matière de gestion d'erreur.
III. Activer/Désactiver le workflow déployé en tant que Feature▲
Si vous avez bien exécuté toutes les étapes décrites dans les sections précédentes, vous devriez retrouver votre workflow dans la partie Site Collection Features de votre collection de sites. Vous pouvez accéder à celle-ci en allant dans Site Actions -> Site Settings -> Site Collection Features
Un des avantages de la Feature est justement la capacité d'activer/désactiver la fonctionnalité qu'elle contient.
IV. Associer le workflow à une liste▲
Lorsque le workflow a été activé, vous devriez pouvoir l'associer à la liste. Ce workflow n'a d'ailleurs pas été conçu pour fonctionner avec une liste en particulier. Il peut en théorie fonctionner avec n'importe quelle liste documentaire car il ne référence aucun champ spécifique non standard.
Le chemin complet pour arriver à l'écran d'association est souligné en rouge sur l'image.
V. Téléchargement▲
Vous pouvez télécharger l'exemple ici