Introduction
Il y a quelques temps, je me suis lancé à la découverte de
Windows Workflow Foundation, et pour dire vrai, plus j’avance dans mon
exploration, plus je prends du plaisir à utiliser ce Framework.
Pour revenir quelques semaines en arrière, voici un exemple
de workflow séquentiel illustré et vraiment très simple. Je vais essayer
d’écrire plusieurs documents sur le sujet, en augmentant le niveau de complexité
à chaque fois, mais toujours dans une optique de « découverte pas à pas ».
Attention, cet article a initialement été écrit avec la Beta
1.2 de Workflow Foundation. Cependant, les modifications et corrections
apportées par la Beta 2 y sont maintenant présentes.
Définitions
Workflow : Un workflow est un ensemble d’actions (étapes)
s’enchainant dans un ordre prédéfinit. Ces actions peuvent s’enchainées en
fonction de conditions, d’interactions avec des processus informatiques ou en
fonction d’interactions humaines.
Activité : Une activité est un composant réutilisable
représentant une étape d’un workflow.
Problématique
Pour cet exemple, l’objectif sera de réaliser une application
console simple qui déclenchera un workflow capable d’afficher un Nom et un
Prénom spécifiés par l’utilisateur.
Evidemment, un projet d’une telle complexité ne nécessite en
principe pas l’utilisation d’un workflow, mais cela fait une bonne base de
départ avant de se diriger vers des horizons plus sombres.
Conception
1. Création du projet
La première étape, après avoir téléchargé (j’ai mis le lien
en fin d’article), installé Windows Workflow Foundation et lancé Visual Studio
2005 est de créer un projet de type workflow (attention, les captures d’écran
sont faites avec la beta 1.2 de WWF).

Plusieurs templates sont proposée :
- Sequential Workflow Console Application, celui qui nous
intéresse et qui va permettre de créer une application qui à la fois définira et
exécutera le workflow. Un workflow séquentiel va permettre de définir une liste
d’actions devant s’enchainer.
- Sequential Workflow Library, une DLL qui ne contiendra que le Workflow qui
pourra être exécuté/hébergé par une application quelconque (Winform, Webform…).
- Workflow Activity Librairy, qui va permettre de définir vos propres composants
d’activités afin de compléter ceux présents par défaut (par exemple définir des
déclencheurs d’action sur vos applications existantes).
- State Machine Console Application, qui va vous permettre de modéliser une
machine à états, utile par exemple pour des applications de suivit de commande
ou de validation.
- State Machine Workflow Library, l’équivalent sans la console.
- Empty Workflow Projet, le bon vieux projet vide qui est souvent la meilleure
base de départ.
Pour cette première démonstration, nous utiliserons une
application console contenant un workflow séquentiel afin de ne pas soulever de
problématique concernant son hébergement et son exécution.
Le projet créé s’ouvre sur un designer, on remarque qu’il
contient plusieurs fichiers :

Tout d’abord, un fichier « Program.cs » qui définit
l’application console en charge de l’hébergement et de l’exécution de notre
workflow. Il s’agira de notre point d’entrée pour envoyer plus tard des
paramètres d’initialisation à notre workflow.
Parmi la quinzaine de ligne de code générée automatiquement,
on retiendra les plus intéressantes, celles qui vont permettre de déclencher le
workflow:
WorkflowRuntime workflowRuntime = new
WorkflowRuntime();
En Beta 1.2 :
Type type = typeof(MySimpleWorkflow.Workflow1);
workflowRuntime.StartWorkflow(type);
En Beta 2 :
Type type = typeof(MySimpleWorkflow.Workflow1);
WorkflowInstance instance = workflowRuntime.CreateWorkflow(type);
instance.Start();
On créé le Runtime du workflow, on l’active et on lui demande
de démarrer un workflow de type “Workflow1”. Workflow1 correspond au fichier de
définition de workflow créé par défaut avec le projet, nous allons nous
empresser de changer son nom.
Une fois le nom du fichier changé, il ne faut pas oublier de
modifier le type du Workflow que nous souhaitons démarrer dans notre application
console : « Type type = typeof(MySimpleWorkflow.MyWorkflow); ». Vous remarquez
ici que c’est le nom du fichier qui définit son type.
Le workflow en lui-même est représenté par deux fichiers : un
nom.designer.cs qui va contenir les informations de modélisation graphique du
workflow, générées automatiquement au fur et à mesure de sa conception ; et un
nom.cs qui va lui contenir le code utilisateur (l’endroit ou nous allons pouvoir
rajouter nos propres traitements). Les deux fichiers définissent la même classe
« MyWorkflow » via un système de classes partielles (nouveauté de .NET 2.0 qui
permet de diviser une classe en plusieurs fichiers).
Nous pouvons compiler et exécuter le programme, une
application console se lance et rien ne se passe, tout fonctionne donc
correctement !
2. Ajout d’une activité simple
Nous allons maintenant pouvoir passer à l’étape suivante:
envoyer des paramètres à notre Workflow et lui faire exécuter une action en
utilisant ceux-ci.
Au niveau de notre application console, il suffit de définir
une liste de paramètres à envoyer au démarrage de notre Workflow. Cette liste
est représentée par un Dictionnaire contenant des clés (string) et des valeurs (object).
Console.WriteLine("Votre nom");
string nom = Console.ReadLine();
Console.WriteLine("Votre prenom");
string prenom = Console.ReadLine();
Dictionary<string, object> namedArgumentValues =
new Dictionary<string, object>();
namedArgumentValues.Add("nom", nom);
namedArgumentValues.Add("prenom", prenom);
Type type = typeof(MySimpleWorkflow.MyWorkflow);
WorkflowInstance instance = workflowRuntime.CreateWorkflow(type,
namedArgumentValues);
instance.Start();
Comme vous pouvez le constater, au moment ou nous allons
démarrer notre workflow, nous spécifions en plus du type notre dictionnaire de
paramètres.
Il faut maintenant préparer notre Workflow à recevoir nos
arguments.
En BETA 1.2 :
Pour ceci, dans le designer de celui-ci, au niveau des propriétés générales du
Workflow, on remarque la possibilité de spécifier des paramètres :


Comme vous pouvez le constater, il suffit de définir le nom,
le type et la direction de vos paramètres. Pour cet exemple je vais travailler
uniquement avec des paramètres d’entrée, donc ayant la direction « In ».
Attention à ce niveau de bien respecter la « case » (majuscules/minuscules), que
cela soit pour le nom ou le type au risque de tomber sur une erreur du style :
« Unhandled Exception: System.ArgumentException: Workflow Services semantic
error: The schedule 'MyWorkflow' has no parameter named 'prenom'.”
En BETA 2:
Il n’est plus possible de définir les variables graphiquement, il suffit de les
declarer au niveau du code du Workflow et l’assignation des parameters aux
variables se fera automatiquement lors de l’initialisation du Workflow:
private string _nom;
public string nom
{
get { return _nom; }
set { _nom = value; }
}
private string _prenom;
public string prenom
{
get { return _prenom; }
set { _prenom = value; }
}
Il ne nous manque plus qu’a utiliser ces paramètres au niveau
de notre workflow. La prochaine étape va donc être de les afficher. Pour ceci,
toujours dans notre designer, il va suffire de rajouter une activité de type «
Code ».

Vous pouvez ici remarquer qu’il existe de base un petit peu
plus d’une 20aine d’activités, dans un prochain article j’illustrerai la
facilitée de développer votre propre activité.
Quelques paramétrages vont être nécessaires avant de pouvoir
écrire notre bout de code, au niveau des propriétés de notre activité de code :
- Renommer l’ID pour une meilleure compréhension au niveau du designer (ici en
AfficheNomPrenom)
- Nommer le bout de code à exécuter en générant un handler : deux solutions sont
possibles : cliquer sur generate Handlers en bas des propriétés de l’activité ou
aller double clicker sur Execute Code dans son gestionnaire d’événements (ici
notre méthode s’appele AfficheNomPrenom_ExecuteCode).

Il ne reste ensuite plus qu’à écrire les lignes de code
représentant l’action à entreprendre. A ce niveau on peut imaginer faire tout ce
que l’on souhaite, de l’envoie d’Emails à des requêtes dans une base de données
en passant par de la génération de fichiers. Pour cet exemple, nous allons nous
contenter d’afficher sur la console le nom et le prénom entrés en paramètre.
En BETA 1.2
private void AfficheNomPrenom_ExecuteCode(object
sender, EventArgs e)
{
Console.WriteLine("Hello, {1} {0}",
this.Parameters["nom"].Value,
this.Parameters["prenom"].Value);
}
En BETA 2
private void AfficheNomPrenom_ExecuteCode(object
sender, EventArgs e)
{
Console.WriteLine("Hello, {0} {1}", nom, prenom);
}
Il ne nous reste plus qu’a exécuter et vérifier que tout
fonctionne.

Pour cet exemple le workflow affiche directement sur la
console, mais dans la plupart des cas, c’est l’application host qui devra
s’occupé d’afficher les valeurs renvoyées par son workflow (donc le fichier
Program.cs).
3. Rajout d’une boucle conditionnelle
Pour terminer l’exemple, nous allons rajouter une boucle (while)
afin d’afficher plusieurs fois cette phrase. Il suffit d’ajouter à notre
workflow une activité de type « while » et de la paramétrer.


Au niveau des conditions, deux possibilités s’offrent à nous
:
- Utiliser le gestionnaire graphique de condition (Rules.RuleConditionReference),
qui offre un assistant très pratique pour définir sa condition, puis enregistrer
cette dernière dans un fichier « rules.xoml » Cette méthode graphique est rapide
lorsque vous devez réaliser des conditions simples.

- ou définir une méthode renvoyant un booloean (CodeCondition)
chargée de la vérification de la condition. Cette méthode va être plus
appropriée pour des vérifications complexes et plus personnalisées.
Malgré le fait que la première méthode soit la plus
appropriée, nous allons utiliser la deuxième (la première est bugée dans la Beta
1.2 et empêche la compilation du projet, mais fonctionne sans problème en Beta
2).
Voici donc le bout de code représentant la méthode :
En BETA 1.2
public int compte = 0;
bool checkIfInfCinq(object sender, EventArgs e)
{
if (compte >= 5)
return false;
else
return true;
}
En Beta 2
public int compte = 0;
void checkIfInfCinq(object sender, ConditionalEventArgs e)
{
if (compte <= 5)
{
compte++;
e.Result = true;
}
else
e.Result = false;
}
On peut maintenant lier notre méthode à notre activité:

Voila, il ne reste plus qu’à exécuter une action à chaque
tour de ma boucle, pour l’exemple je vais me contenter de re-exécuter la méthode
qui affiche le nom et le prénom, en ayant bien sur rajouté à celle-ci une ligne
de code afin d’incrémenter mon compteur.

On teste une dernière fois, et tout fonctionne !

C’est terminé, comme vous pouvez le constater, ce n’est pas
bien compliqué de faire un workflow simple (et inutile…).
Florent SANTIN