Résumé:
WCF pour Windows Communication Foundation est l’une de quatre nouvelles briques apportées par .NET Framework 3.0. Cette brique unifie le développement des applications distribuées. Cet article présentera les bases de cette plateforme avec un exemple concret d’application en mode de client-service.
Belle journée en perspective (encore faudrait il que j’arrive à finir mon article français/anglais sur WCF 🙂 ) avec la sortie en version RTM* du .NET Framework 3.0 et du Windows SDK for Vista.
Toujours dans les news, notez la sortie du Microsoft ASP.NET AJAX Extention (ex-Atlas) en version Beta 2 ainsi que les sorties RTM d’Office 2007 et des VSTO (Visual Studio Tools for Office).
Le contrôle MediaElement que j’ai decouvert au cours de cette semaine a revolutionné ma petite vie de developpeur 🙂 Ce contrôle permet de contenir des images, sons ou videos.
Pour charger un media, rien de plus simple :
1
2
MediaElement monMedia=newMediaElement();
monMedia.Source=newUri("monURI");
Sachant que mon Uri peut pointer sur un fichier local (c:\….) ou distant (http://…..) que se soit une video, une image ou un son….
Le media sera joué immédiatement. Bien que vous disposez des methodes Play(), Stop() et Pause() pour contrôler le media, utilisez plutot la proprieté LoadedBehavior qui permet de definir et/ou obtenir l’etat du media :
1
2
3
monMedia.LoadedBehavior=MediaState.Pause;//Pause
monMedia.LoadedBehavior=MediaState.Stop;//Arret
monMedia.LoadedBehavior=MediaState.Play;//Play
A ce sujet, pour pouvoir jouer une video (ou son) en boucle, la seule doc que j’avais trouvé sur le msdn2 était de mettre un MediaTimeline. Chose un peu tordu dans le code alors qu’il y a une solution toute simple :
1) Abonnez-vous à l’evenement MediaEnded (fin du media) :
1
2
monMedia.MediaEnded+=
newRoutedEventHandler(monMedia_MediaEnded);
2) Remettez la position du media à zero (debut) et relancez le media :
C’est bien beau tout ca, mais la vous n’avez aucun apercu à l’ecran ce qui est quand meme un peu dommage ^^ Mais là où ca devient fort bien interressant, c’est qu’un VisualBrush peut prendre en parametre un MediaElement pour pouvoir remplir un rectangle par exemple :
1
2
Rectangle monRectangle=newRectangle();
monRectangle.Fill=newVisualBrush(monMedia);
Et hop la, votre video (par exemple) sera joué dans ce rectangle. Enfin pour rajouter votre rectangle à un canvas que vous aurez au préalable placé dans votre code XAML :
1
monCanvas.Children.Add(monRectangle);
A partir de la on peut vraiement s’amuser et aller plus loin dans la démarche.. Par exemple, les rectangles ont une proprieté Clip qui va nous permettre de clipper notre media, OpacityMask pour appliquer un masque d’opacité, et bien d’autre chose pour appliquer differents effets a notre rectangle/video, … Et encore je ne parle que des rectangles, a partir du moment où votre controle pourra etre remplit par un VisualBrush on pourra tout y mettre 🙂
Je ne vais pas vous devoiler sur ce quoi je travaille en ce moment, mais il faut bien se rendre compte de tout ce qu’on peut faire avec car c’est carrement dément…
Windows Workflow Foundation propose deux services fort utile qui sont le Tracking et la Persistance.
La persistance va permettre d’enregistrer l’instance d’un workflow en dur dans un serveur SQL. On va pouvoir grace a cela, demarrer une instance de workflow depuis une application host, la quitter, puis la reprendre a tout moment. La persistance devient alors très utile, imaginez un workflow de gestion d’article qui demarre au moment où un article serait posté et attendrait la validation des admins pour etre publié. Il serait alors fort utile de pouvoir enregistrer et reprendre le workflow quand on le souhaite pour que les admins puissent donner leur reponse à tout moment.
La persistance sous WF est très simple a mettre en oeuvre :
Il faut d’abord préparer la base de données en executant les scripts SQL qui se trouvent dans C:\WINDOWS\WinFX\v3.0\Windows Workflow Foundation\SQL\EN. Il y a 4fichiers : 2 pour les schémas et 2 pour la logique pour la persistance et le tracking. Executez les schémas en 1er biensûr 🙂
Ensuite pour activer la persistance dans votre workflow, ajoutez le service SqlWorkflowPersistenceService à votre runtime. ex:
Vous recuperez une collection de SqlPersistenceWorkflowInstanceDescription où vous allez pouvoir recuperer des informations comme son status, son ID d’instance, etc…
Enfin pour récupérer une instance :
où _instanceID est un Guid qui correspond à l’ID de l’instance à resumer.
Le Tracking quant à lui, permet de « traquer » un workflow en enregistrant des tas de parametres sur son déroulement. Pour le mettre en place, c’est aussi facile que pour la persistance. Assurez-vous d’avoir bien créé les tables (scripts Tracking_Logic et Tracking_Shema). Ensuite tout comme la persistance, il faudra ajouter le service tracking à la runtime par le code :
Ce code vous retournera une List(Of SqlTrackingWorkflowInstance) (autopub: explication des List ici) :))
L’objet SqlTrackingQueryOptions permet quant à lui, d’imposer des conditions de recherche. L’exemple ci-dessous permet de recuperer seulement les instances en cours (running) :
1
2
3
4
Dimstq AsNewSqlTrackingQuery(CONNSTRING)
Dimopt AsNewSqlTrackingQueryOptions()
opt.WorkflowStatus=WorkflowStatus.Running
Return stq.GetWorkflows(opt)
L’objet SqlTrackingWorkflowInstance contient toutes les informations sur une instance de Workflow. On y trouve les propriètés ActivityEvents (evenement des Activity), Status, UserEvents (evenement des utilisateurs comme par exemple les traces laissées par les TrackData dans le workflow), WorkflowInstanceId, etc…
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 :
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 :
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.
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
ModuleModule1
SubMain()
'Instanciation de la couche service
Dimservice AsNewService()
' 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()
EndSub
EndModule
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.
Dans mon petit post d’introduction à WF, je vous avais parlé et donné le lien de WFPad. Malheureusement, la version de ce soft ne marche pas avec la Beta 2 de WF.
Je vous mets donc à disposition, la nouvelle release de WFPad que j’ai un peu modifé (commenté une ligne qui posait problème) : DOWNLOAD HERE
Pour rappel, WFPad est un projet opensource ecrit en C# qui permet la visualisation et l’édition en mode graphique de code XOML (…de Workflow) 🙂
Le post officiel avec les sources de Mark Schmidt’s : CLICK HERE