Workflow Foundation–Tutoriel 1.2–Création d’un Workflow Simple

L’objectif de ce tutoriel, associé au premier cours, est d’apprendre à utiliser le designer de WF. Le but aussi est de passer des informations au workflow comme arguments en entrée et recevoir le résultat comme argument de sortie. Le but du workflow est de faire la somme de deux nombres. Etape 1 – Création de la solution L’objectif de cette étape est de créer une application console « Workflow ». Lancer VS 2012 Cliquez sur « Fichier à Nouveau à Projet » Choisissez le template « Application Console Workflow » Appelez la solution « SommeWorkflow » Cliquez sur « OK » Etape 2 : Création du workflow L’objectif de cette étape est d’utiliser le designer du workflow pour ajouter les différentes activités. Les arguments et les expressions seront aussi déclarés dans le designer. Remarquez dans l’explorateur de solutions que la solution contient « Program.cs » et « workflow1.xaml » Renommez « workflow1.xaml » en « SommeActivity.xaml » Cliquez sur la zone blanche du « Designer » Dans la fenêtre de propriété, affectez « SommeActivity » à la propriété « Name » En dessous du designer, cliquez sur « Arguments », la grille de saisie des arguments apparait. Entrez trois arguments de type « Int32 » appelés respectivement : « Nombre1 » , « Nombre2 » et « Resultat » Les deux premiers arguments doivent être de type « In » et le dernier de type « Out » A partir de la barra à outils, glissez une activité « WriteLine » Dans la zone « Text » entrez « Bienvenue à la formation WF4.5 » (inclure les guillemets) Faites glisser une autre activité de type « WriteLine » juste en dessous de la première Dans la zone Text, entrez l’expression suivante : string.Format("Vous avez entré {0} et {1}", Nombre1, Nombre2) Remarquez qu’une activité de type « Sequence » s’est automatiquement créée et contient les deux activités En dessous du deuxième « WriteLine » faites glisser une activité de type « Assign » Dans la zone « To », entrez « Resultat » Dans la deuxième zone, entrez Nombre1 + Nombre2 Remarquez la présence d’Intellisense dans le designer using System.Collections.Generic; Etape 3 : Exécution du workflow et passage d’informations Dans cette étape nous allons passer deux nombre en entrée au workflow après nous récupèrerons et afficherons le résultat. Le passage d’information peut se passer directement en utilisant des propriétés créées par le designer. Mais une autre façon est de créer un dictionnaire indexé par les chaînes de caractères et qui contient des objets. Le dictionnaire a comme clé le nom de la variable et pour valeur, le contenu de cette variable. Dans la zone des « using », ajoutez un «using » pour l’espace de noms System.Collections.Generic using System.Collections.Generic; Juste avant l’invocation créez un dictionnaire indexé par « String » et contenant des objets « Object » appelé « entree » En utilisant la méthode « Add », ajoutez deux nombres (25,26) indexés par les noms de variable « Nombre1 » et « Nombre2 » var entree = new Dictionary<string, object>();entree.Add("Nombre1", 26);entree.Add("Nombre2", 25); Changez l’invocation de la méthode « Invoke » en récupérant son résultat dans une variable de type « IDictionary<string,object> » appelée « sortie » Affichez le résultat en accédant à la variable indexée par « Resultat » dans le dictionnaire « sortie » Le code complet de la fonction « Main » devrait être comme celui-ci : static void Main(string[] args) { Activity workflow1 = new SommeActivity(); var entree = new Dictionary<string, object>(); entree.Add("Nombre1", 26); entree.Add("Nombre2", 25); IDictionary<string,object> sortie = WorkflowInvoker.Invoke(workflow1, entree); Console.WriteLine(sortie["Resultat"]); Console.ReadKey(); } Le ReadKey de la fin sert à suspendre la console pour pouvoir voir les résultats Exécutez l’application en appuyant sur « F5 »

Tutoriel 1.1 : Découverte de Workflow Foundation 4.5

L’objectif de ce tutoriel, relatif au premier cours, est de découvrir la structure d’une application WF 4.5 et les différentes façons de créer un workflow pour ensuite, l’exécuter. Etape 1 – Ouverture de la solution et son exécution L’objectif de cette étape est d’ ouvrir la solution de démonstration de ce module. Lancer VS 2012 Choisir Fichier -> Ouvrir -> Projet Solution Naviguez jusqu’au répertoire de démonstrations Ouvrez la solution « Demo1.sln », il s’agit d’une application console En utilisant l’explorateur de solutions, ouvrez le fichier « Program.cs » Le listing de ce fichier devrait être comme ceci : class Program { static void Main(string[] args) { Console.WriteLine("--------------------------------------"); Console.WriteLine("Workflows séquentiels"); Console.WriteLine("--------------------------------------"); var w1 = new TransactionBancaireWorkflow(); w1.Montant = 55000; IDictionary<string, object> result = WorkflowInvoker.Invoke(w1); Console.WriteLine("Commission : {0}", result["Commission"]); Console.WriteLine("--------------------------------------"); Console.WriteLine("Diagrammes de flux"); Console.WriteLine("--------------------------------------"); var w2 = new TransactionBancaireDFWorkflow(); w2.Montant = 9000; result = WorkflowInvoker.Invoke(w2); Console.WriteLine("Commission : {0}", result["Commission"]); Console.WriteLine("--------------------------------------"); Console.WriteLine("Diagrammes de machine d'états"); Console.WriteLine("--------------------------------------"); var w3 = new TransactionValidationWorkflow(); w3.Montant = 59000; var app = new WorkflowApplication(w3); app.Run(); Console.WriteLine("appuyez sur une touche pour valider le workflow"); Console.ReadKey(); app.ResumeBookmark("signet", null); Console.WriteLine("--------------------------------------"); Console.WriteLine("Workflow créé par code"); Console.WriteLine("--------------------------------------"); var w4 = GetCodeWorkflow(); WorkflowInvoker.Invoke(w4); Console.WriteLine("--------------------------------------"); Console.WriteLine("Workflow chargé à partir d'un fichier XML"); Console.WriteLine("--------------------------------------");   var w5 = ActivityXamlServices.Load("wf5.xaml"); WorkflowInvoker.Invoke(w5); Console.ReadKey(); }   private static Activity GetCodeWorkflow() { var workflow = new Sequence() { }; workflow.Activities.Add(new WriteLine() { Text = "Un workflow créé par code !" }); return workflow; } } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Exécutez l’application en appuyant sur F5 Lorsqu’un message demandant d’appuyer sur une touche apparaît, appuyez sur n’importe quelle touche Etape 2 – Accès à un workflow séquentiel L’objectif de cette étape est de voir la structure et de comprendre l’exécution d’un workflow séquentiel. A partir de l’explorateur de solutions, ouvrez le fichier « TransactionBancaireWorkflow.xaml » Remarquez le workflow chargé dans le designer graphique Remarquez que le workflow est décomposé d’une instruction conditionnelle (if) composée à son tour de deux branches « if » et « else » La première branche calcule la commission à partir du montant (0.2%) si le montant dépasse 50000. Ensuite elle affiche le message indiquant que l’opération a besoin de validation. La deuxième branche affecte une valeur de zéro à la variable commission. En dessous de la fenêtre du designer, cliquez sur le lien « Arguments » Remarquez la présence de deux arguments, l’un appelé « Montant » et l’autre « Commission ». Les deux arguments sont de type « Decimal » Remarquez que l’argument « Montant » est en entrée et que l’argument « Commission » est en sortie. Revenez au fichier « Program.cs », examinez comment un workflow a été instancié : var w1 = new TransactionBancaireWorkflow() ; .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Les workflows sont créés comme n’importe quel object C#, en utilisant l’opérateur « new » L’instruction suivante montre comment un environnement externe (le programme) fournit les valeurs des arguments en entrée du workflow (Montant). Il s’agit d’une simple affectation car un alias de propriété est créé pour « Montant ». w1.Montant = 55000 ; L’instruction suivante exécute le workflow. Une nouveauté de WF 4.5 est que c’est devenu très simple d’exécuter un workflow, juste en utilisant la classe « WorkflowInvoker » et la méthode « Invoke ». Remarquez que la méthode « Invoke » renvoir un dictionnaire d’objets. Il s’agit des arguments en sortie créés par le workflow. IDictionary<string, object> result = WorkflowInvoker.Invoke(w1); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Pour accéder ensuite à la valeur de commission, nous utiliserons la variable “result” Console.WriteLine("Commission : {0}", result["Commission"]); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Changez le workflow en changeant le montant maximum (50000) dans le designer et/ ou en changeant l’argument « Montant » fourni dans « Program.cs à Main » Etape 3 : Accès à un workflow diagramme de flux L’objectif de cette étape est de découvrir un autre type de workflows : les diagrammes de flux En utilisant l’explorateur de solution, ouvrez le fichier « TransactionBancaireDFWorkflow.xaml » Remarquez que le workflow est graphiquement différent du workflow précédent mais fonctionnellement équivalent Remarquez que ce workflo a les mêmes arguments que le workflow précédent. De la même façon, l’argument « Montant » est fourni en utilisant une affectation et le workflow est exécuté en utilisant « WorkflowInvoker » var w2 = new TransactionBancaireDFWorkflow(); w2.Montant = 9000; result = WorkflowInvoker.Invoke(w2); Console.WriteLine("Commission : {0}", result["Commission"]); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Changez le montant en entrée et / ou le plafond de validation dans le workflow puis rééexéutez le programme Etape 4 : Accès à un workflow d’états L’objectif de cette étape est de découvrir les workflows de machine d’état qui permettant de transiter un workflow d’un état à un autre jusqu’à atteindre un état final. L’objectif est d’utiliser aussi certaines fonctionnalités du designer. En utilisant l’explorateur de solutions, ouvrez « TransactionValidationWorkflow.xaml » Remarquez que le workflow est graphiquement différent des deux premiers Remarquez que le workflow démarre par un état initial A partir de l’état initial, la transition « T1 » met le workflow dans un état « AttenteVal » tandis que la transition « T2 » le met dans un état final Cliquez sur la transition « T1 » puis sur la fenêtre de propriétés Remarquez que la transition « T1 » a pour condition que le montant soit supérieur à 50000 De la même façon, consultez la condition de la transition « T2 » Affichez les arguments du workflows Vérifiez que le workflow possède un argument en entrée « Montant » de type « Decimal » Dans le workflow, doublez-cliquez sur l’état « AttenteVal » Dans la zone de texte « Zoom » en dessous, entrez « 70% » Remettez le zoom à « 100% » Remarquez que le workflow dépasse le cadre de la fenête Naviguez dans le workflow en utilisant le bouton « Vue d’ensemble » ou « Overview » située en bas à droite de l’écran Remarquez en haut de l’écran, les liens permettant de naviguer dans les niveaux du workflows. Le lien indique qu’on est dans l’activité « AttenteVal » qui est elle-même enfant d’une autre activité « StateMachine » représentant le workflow Remarquez que l’activité est composée d’une entrée et d’une sortie (entrée de l’état et sortie de l’état). L’entrée est composée d’une séquence qui est elle-même composée d’un affiche puis d’une activité Pick. A l’intérieur de la zone « Trigger » de Pick, il y a une activité « Attendre ». L’activité « Attendre » n’est pas une activité native. C’est une activité que nous avons nous-mêmes développés. Son implémentation est dans le fichier « Attendre.cs » public sealed class Attendre : NativeActivity<object> { protected override void Execute(NativeActivityContext context) { context.CreateBookmark("signet");     }   protected override bool CanInduceIdle { get { return true; } } } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Remarquez la présence de l’activité « Attendre » dans la boîte à outils L’activité attendre crée un signet (Bookmark) qui bloque le workflow en attendant une action de l’utilisateur . Dès qu’un utilisateur tape une touche, le workflow reprend son activité. Remarque dans « Program.cs » que le workflow n’est pas exécuté par WorkflowInvoker mais par la classe « WorkflowApplication » var w3 = new TransactionValidationWorkflow(); w3.Montant = 59000; var app = new WorkflowApplication(w3); app.Run(); Console.WriteLine("appuyez sur une touche pour valider le workflow"); Console.ReadKey(); app.ResumeBookmark("signet", null); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Etape 5 : Accès à un workflow créé par code L’objectif de cette étape est de voir comment un workflow est créé par code sans passer par le designer. A partir de l’explorateur de solutions, ouvrez le fichier « Program.cs » Consultez la méthode « GetCodeWorkflow » private static Activity GetCodeWorkflow() { var workflow = new Sequence() { }; workflow.Activities.Add(new WriteLine() { Text = "Un workflow créé par code !" }); return workflow; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } La méthode crée une activité de type « Sequence » puis ajoute une activité « WriteLine » a ses enfants Le workflow est normalement exécuté par « WorkflowInvoker » comme pour les workflows créés par designer var w4 = GetCodeWorkflow(); WorkflowInvoker.Invoke(w4); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Etape 6 : Chargement d’un workflow à partir d’un fichier L’objectif de cette étape est de créer un workflow qui a été ultérieurement enregistré dans un fichier « XAML ». Dans l’explorateur de solutions, cliquez sur le bouton droit sur le projet « Demo1 » Cliqez sur « Ouvrir le dossier dans l’explorateur de fichiers » Dans l’explorateur accédez au dossier « bin à debug » Ouvrez le fichier « wf5.xaml » dans le bloc notes et examinez son contenu <Activity mc:Ignorable="sap sap2010 sads" x:Class="Demo1.XmlWorkflow" sap2010:ExpressionActivityEditor.ExpressionActivityEditor="C#" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sads="http://schemas.microsoft.com/netfx/2010/xaml/activities/debugger" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:sap2010="http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation" xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <TextExpression.NamespacesForImplementation> <sco:Collection x:TypeArguments="x:String"> <x:String>System</x:String> <x:String>System.Collections.Generic</x:String> <x:String>System.Data</x:String> <x:String>System.Linq</x:String> <x:String>System.Text</x:String> </sco:Collection> </TextExpression.NamespacesForImplementation> <TextExpression.ReferencesForImplementation> <sco:Collection x:TypeArguments="AssemblyReference"> <AssemblyReference>Microsoft.CSharp</AssemblyReference> <AssemblyReference>System</AssemblyReference> <AssemblyReference>System.Activities</AssemblyReference> <AssemblyReference>System.Core</AssemblyReference> <AssemblyReference>System.Data</AssemblyReference> <AssemblyReference>System.Runtime.Serialization</AssemblyReference> <AssemblyReference>System.ServiceModel</AssemblyReference> <AssemblyReference>System.ServiceModel.Activities</AssemblyReference> <AssemblyReference>System.Xaml</AssemblyReference> <AssemblyReference>System.Xml</AssemblyReference> <AssemblyReference>System.Xml.Linq</AssemblyReference> <AssemblyReference>mscorlib</AssemblyReference> <AssemblyReference>Demo1</AssemblyReference> </sco:Collection> </TextExpression.ReferencesForImplementation> <WriteLine Text="Un workflow chargé à partir d'un fichier" sap2010:WorkflowViewState.IdRef="WriteLine_1" sads:DebugSymbol.Symbol="dzxGOlxGb3JtYXRpb25XRlxEZW1vc1xDaGFwaXRyZSAxXERlbW8xXERlbW8xXFhtbFdvcmtmbG93LnhhbWwCIwMjlwECAQEjEyMzAgEC" /> <sap2010:WorkflowViewState.IdRef>Demo1.XmlWorkflow_1</sap2010:WorkflowViewState.IdRef> <sap2010:WorkflowViewState.ViewStateManager> <sap2010:ViewStateManager> <sap2010:ViewStateData Id="WriteLine_1" sap:VirtualizedContainerService.HintSize="211,62" /> <sap2010:ViewStateData Id="Demo1.XmlWorkflow_1" sap:VirtualizedContainerService.HintSize="251,142" /> </sap2010:ViewStateManager> </sap2010:WorkflowViewState.ViewStateManager> </Activity> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Revenez dans Visual Studio puis ouvrez le fichier « Program.cs » Remarquez comment le workflow est chargé à partir du fichier précédent var w5 = ActivityXamlServices.Load("wf5.xaml"); WorkflowInvoker.Invoke(w5); Dans le fichier xaml, changez la propriété Text de la balise WriteLine Rééxécutez « Demo1 » pour voir le résultat Conclusion Et voilà, en mode découverte, vous avez vu comment exécuter plusieurs types de workflows et aussi les différents modes de création. Je reviendrai avec d’autres tutoriaux qui iront plus en détail sur la conception de workflows. Vous pouvez télécharger la démo ici Enjoy !