« Dev »

HandleExternalEvent & CallExternalMethod sous Workflow Foundation

6 août 2006

Les Activity HandleExternalEvent & CallExternalMethod, sont tout deux indispensable dans le developpement de workflow. Ce sont en quelque sorte les entrées-sorties entre le workflow et le programme host.

Le HandleExternalEventActivity va pemettre de marquer une pause dans le deroulement d’un workflow en attendant le déclement d’un evenement. Le CallExternalMethodActivity va quand à lui effectuer en quelque sorte l’opération inverse, à savoir, déclencher l’appel d’une methode externe au workflow.

Les methodes et evenement vont devoir etre défini dans une interface marquée par l’attribut ExternalDataExchange. Le programme host, lui, devra ajouter le service ExternalDataExchangeService

Mission 1 : Création du projet DTO pour les objets communs

1) Créons donc un nouveau projet de type Class Library en VB.net. Nous allons commencer tout d’abord par ajouter une référence au Workflow Foundation qui est : System.Workflow.Activities

2) Ensuite créons une classe nommé MyEventArgs qui nous pemettra de passer des arguments dans notre evenement. Nous allons, dans cette classe, stocker un petit message, il faudra donc créer un champ et une propriété de type String nommé Message.
Cette classe doit être Serializable et doit hériter de la classe System.Workflow.Activities.ExternalDataEventArgs. Il faudra donc dans le code du constructeur ajouter un MyBase.New(instanceId) avec comme instanceId, l’instance de notre workflow en Guid pour que l’evenement puisse etre mappé sur la bonne instance de workflow.
Notre classe pourrait ressembler à cela :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Serializable()> _
Public Class MyEventArgs
     Inherits System.Workflow.Activities.ExternalDataEventArgs
 
     Private m_Message As String
     Public Property Message() As String
         Get
             Return m_Message
         End Get
         Set(ByVal value As String)
             m_Message = value
         End Set
     End Property
 
     Sub New(ByVal instanceId As Guid, message as String)
         MyBase.New(instanceId)
         m_Message = message
     End Sub
 
 End Class

3) Créons maintenant notre Interface de communication que l’on nommera dans notre exemple : ICommunication.
L’interface doit être marquée par l’attribut System.Workflow.Activities.ExternalDataExchange().
Nous allons définir une methode nomme MaMethode qui prendra en argument un message en string et un evenement nommé MonEvenement de type MyEventArgs créé juste avant :) . Le code pourrait être :

1
2
3
4
5
<System.Workflow.Activities.ExternalDataExchange()> _
Public Interface ICommunication
     Sub MaMethode(ByVal message As String)
     Event MonEvenement As EventHandler(Of MyEventArgs)
End Interface

4) Pour finir, compiler votre projet DTO et passons à la création du workflow

Mission 2 : Création du workflow

1) Commencons par créer un nouveau projet dans notre solution de type Sequential Workflow Library et ajouter la référence au projet DTO.

Notre workflow va ressembler à ca :

Au démarrage, il attend l’evenement MonEvenement (Activity HandleExternalEvent) qui contient un message via la classe MyEventArgs , puis quand l’evenement est recu, appel MaMethode (Activity CallExternalMethod) en passant en parametre le message contenu dans notre evenement.

Plutot qu’un long baratin, la démo en video :

Mission 3 : Création de la couche service

Il ne vous plus qu’a créer la couche service qui s’occupera de démarrer le runtime et les instances de votre workflow. C’est elle aussi qui implémentra l’interface ICommunication.

Ici, notre couche service sera tres simple. Elle disposera des methodes StartRuntime et StartInstance pour demarrer le runtime du WF et l’instance de notre workflow. La methode DeclencherEvent s’occupera de declencher l’evenement. De plus, elle implementra notre interface ICommunication (methode MaMethode et evenement MonEvenement). A noter que lors de la creation de notre runtime, nous avons ajouter le service ExternalDataExchangeService pour pouvoir communiquer avec notre workflow via notre Interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Public Class Service
     Implements DTO.ICommunication
 
     Dim runtime As Workflow.Runtime.WorkflowRuntime
     Dim instance As Workflow.Runtime.WorkflowInstance
 
     Sub StartRuntime()
         runtime = New Workflow.Runtime.WorkflowRuntime()
         Dim eds As New Workflow.Activities.ExternalDataExchangeService()
         runtime.AddService(eds)
         eds.AddService(Me)
         runtime.StartRuntime()
     End Sub
 
     Sub StartInstance()
         instance = runtime.CreateWorkflow(GetType(WorkflowDemo2.Workflow1))
         instance.Start()
         Console.WriteLine("InstanceId {0} demarrée", instance.InstanceId.ToString())
     End Sub
 
     Sub DeclencherEvent(ByVal message As String)
         RaiseEvent MonEvenement(Nothing, New DTO.MyEventArgs(instance.InstanceId, message))
     End Sub
 
     Public Sub MaMethode(ByVal message As String) Implements DTO.ICommunication.MaMethode
         Console.WriteLine("MaMethode appelée. Le message est : {0}", message)
     End Sub
 
     Public Event MonEvenement(ByVal sender As Object, ByVal e As DTO.MyEventArgs) _
     Implements DTO.ICommunication.MonEvenement
 
End Class

Mission 4 : Création de la GUI

Ici dans notre projet notre GUI sera en mode console. Elle doit juste faire reference à notre couche service et l’instancier. Le code peut être :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Module Module1
     Sub Main()
         'Instanciation de la couche service
         Dim service As New Service()
         ' Demarrage du Runtime WF
         service.StartRuntime()
         ' Demarrage d'une instance de notre Workflow
         service.StartInstance()
         ' Declenchement de l'evenement
         Console.Write("Message a passer dans l'evenement ? ")
         service.DeclencherEvent(Console.ReadLine())
         ' Fin
         Console.Read()
     End Sub
 End Module

Ce qui donne à l’ecran :

Conclusion

C’est certe un exemple très simple et qui ne sert a rien, mais j’espere avoir pu vous donner quelques tips pour l’utilisation des HandleExternalEvent & CallExternalMethod au sein d’un workflow sous Worfkflow Foundation.

**UPDATE** : les sources du projet ICI

Workflow Foundation: la galère des FaultHandler(s)

14 juillet 2006

Ca fait un peu plus d’une petite semaine que je me suis lancé dans le Windows Workflow Foundation (WF et non WWF ^^), qui est pour moi, ma 1er partie de ma decouverte de .NET 3.0 :)
Je suis entrain de terminer mon article ainsi qu’un Webcast sur une introduction à WF qui devrait être finalisé ce weekend…

En préparant mon Webcast je me suis heurté à un problème avec l’Activity FaultHandler ! Cette activité permet de recupérer les exceptions survenu dans l’execution de votre workflow…

Mon workflow possédait un CodeActivity qui été sensé travailler avec un XmlDocument representant la response d’un Webservice. Mais voila que dans certains cas mon code pouvait lever l’exception XmlException..
J’ai donc placé dans le « Fault View » du designer, un FaultHandler qui checké l’exception XmlException pour executer un CodeActivity qui ecrivait un petit message « Bug :-) )) » ^_^

Mais lorsque je provoquais volontairement l’exception lors de l’execution de mon workflow, celle ci n’etait pas du tout géré par mon FaultHandler et on me renvoyait dans mon code sous VS2005 avec un petit message « XmlException was unhandled by user code » :-(

A partir de là, grosse perte de temps à chercher dans tous les sens sur les peu de sites qui parle de WF…. La solution est en fait toute bête ^^
En effet, VisualStudio est prioritaire sur les FaultHandlers.. C’est à dire que quand votre Workflow est executé en mode debug sous VS2005, en cas d’exception ce n’est pas le FaultHandler qui repondra mais VS2005. Si maintenant vous executez votre application hors contexte VS2005, là vous aurez bien le FaultHandler qui prendra la main :-)

Chose dîte, je retourne sur mon Webcast : Que du bonheur :-D

MySudoku

31 mai 2006

Et voila, ce sur quoi je travaillé ces derniers temps MySudoku est enfin « releasé » et vient d’être publié sur SUPINFO Project comme projet chef d’oeuvre !

MySudoku est un petit jeu du Sudoku développé en C# sous .NET 2 qui reprend les « bases » de mes Sudoku’ Days (n°1n°2) ;-)

Fonctionnalités :

  • Chargement/Enregistrement des grilles
  • Génération automatique de grille
  • Création manuelle de grille
  • Résolveur de grille de tout niveau
  • Fonctions de verification de grille
  • Capture et Impression de grille
  • Application Anglais/Francais
  • Programme d’installation (en francais uniquement) avec installation des codes sources.

Prérequis :

  • Framework .NET 2.0

Le programme d’installation : click here
Les codes sources : click here

C’est bon maintenant je rompe définitivement avec le sudoku :-D

Newsletter au Laboratoire Microsoft

25 mai 2006

Mon cher ami Benuts et moi même sommes fier de vous annoncer en exclusivité la sortie prochaine (fin de semaine?) de la Newsletter au Laboratoire Microsoft (www.labo-microsoft.com) !!! :-D

Benuts se sera occupé de faire la « template », en gros le design et la forme de la Newsletter (le coté visible) et moi comme à mon habitude, la partie background, soit non visible, bref le systeme de génération et d’envoi de la newsletter…

La 1er newsletter sera envoyé à plus de 30.000 destinataires (inscrit sur le site) en fin de semaine théoriquement…

Coté technologique, j’ai utilisé l’ASP.NET 2 pour faire l’application de génération et d’envoi ! J’attire votre attention sur le fait que maintenant, en ASP.NET 2, les classes pour le Mail ne se trouvent plus dans le namespace System.Web.Mail (enfin si, mais le compilo nous informe que cela est obsolete) mais sur le namespace System.Net.Mail !

On y trouve notamment, la classe SmtpClient pour l’envoi et surtout la classe MailMessage pour la génération de l’email. Les propriétés To, CC et Bcc sont maintenant des collections de la classe MailAddress !
De plus, la fonction SendAsync() de la classe SmtpClient fait son apparition, nous permettant d’envoyer le mail de facon asynchrone, donc de facon détaché au thread qui l’appel, bref, comme dirait Redo : QUE DU BONHEUR :-D !

Pour les curieux : la bible MSDN sur le System.Net.Mail
Et biensûr le labo ICI !!!!

Have a nice night :-)

Les collections génériques sous .NET 2.0

19 mai 2006

Résumé:
Dans cet article, nous allons voir les collections génériques introduites avec le nouveau framework .NET 2.0. C’est l’espace de noms (namespace) System.Collections.Generic qui contient les interfaces et classes qui définissent des collections génériques permettant aux utilisateurs de créer des collections fortement typées. Nous verrons dans cet article les différentes collections génériques proposées par le framework 2.0 (dictionnaires, listes, piles, etc…) à travers des explications claires accompagné d’exemple.

Sommaire:

   *  Introduction
    * 1 Les dictionnaires
          o 1.1 Introduction
          o 1.2 Les dictionnaires (Dictionary)
          o 1.3 Les dictionnaires triés (SortedDictionary)
          o 1.4 Les "listes" triées (SortedList)
          o 1.5 Autres collections de type "dictionnaire"
    * 2 Les queues et les piles
          o 2.1 Les queues (Queue)
          o 2.2 Les piles (Stack)
    * 3 Les listes
          o 3.1 Introduction
          o 3.2 L'interface IList
          o 3.3 Manipulation de base des List
          o 3.4 La capacité
          o 3.5 Utilisation des délégations
          o 3.6 Utilisation des prédicats (Predicate)
          o 3.7 Le trie
    * 4 Les listes à double lien (LinkedList)
          o 4.1 Introduction
          o 4.2 Les nœuds : LinkedListNode
          o 4.3 Manipulation
    * Conclusion

Pour ceux qui serait intéressé :