Utiliser la persistance avec Workflow Foundation

Au cours de cet article, nous verrons comment mettre en place le mécanisme de persistance afin de rendre plus fiable l'utilisation de Workflow Foundation au sein de vos applications

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

Les deux auteurs

Profil ProSite personnel

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Présentation

L'une des premières problématiques à laquelle j'ai été confronté en utilisant Workflow Foundation a été de gérer la notion de persistance. Il faut savoir que j'ai débuté avec les workflows à l'aide d'outils dédiés comme StaffWare qui étaient très complets mais aussi très chers et il fallait surtout parfois les personnaliser à l'aide de code...JAVA.
Pour ces deux raisons (véridique), les choix techniques dans l'entreprise dans laquelle je travaille ont été de se tourner vers Workflow Foundation, moins cher, plus facilement utilisable par des concepteurs .Net et surtout plus léger; peut-être même trop léger...

La grande force de Worfklow Foundation, mais aussi sa plus grande faiblesse, est que cela fonctionne comme une "simple méthode", au sein de vos applications. Cela signifie qu'il ne faut pas de serveur dédié, qu'il ne faut pas forcément de base de données dédiée et que le développeur garde entièrement la main sur tout le workflow.

Tout ceci est très beau et très utile sur le papier mais quand on veut garantir une fiabilité de workflow et garantir que tout workflow qui commence est en mesure de se terminer correctement qu'importe les contraintes (application qui se coupe, crash serveur, tremblement de terre), alors cela devient plus délicat. En effet, le Workflow Foundation fait ce qu'on attend d'un moteur de workflow basique mais pas plus.

Or, comme dans quasiment toutes les applications utilisant un workflow, on veut s'assurer que même dans le cas d'un workflow durant moins d'une seconde, si la première tâche de ce dernier s'éxecute et que le serveur crashe par la suite, on veut pouvoir relancer le workflow pour éxécuter la(les) tâche(s) suivantes sans la moindre perte de données et c'est à ce moment là que la notion de persistance entre en jeu.

Comme nous l'avons vu dans l'article précédent, Workflow Foundation n'est pas à proprement parlé un moteur de Workflow, c'est une surcouche du framework .Net qui permet d'implémenter une notion de workflow au sein de vos applications. Workflow Foundation est une mini brique qui ne fait que ce qu'on lui demande et par défaut, cette brique ne fait pas de persistance. Nous allons donc voir au sein de cette article comme mettre en place cette persistance.

1. Intérêt de la persistance

La persistance sera plus ou moins critique selon la durée de vie de votre workflow et des choix techniques que vous ferez. En effet, plus le workflow sera long, plus il sera important de persisté son état. Cette criticité est augmentée par le niveau de fiabilité de l'application qui hébergera votre workflow car plus cette application risque de planter ou d'être fermée prématurément, plus grands sont les risques qu'un workflow en cours d'execution cesse d'un coup sans avoir pu se finir ou enregistrer son état.
La persistance de votre workflow vous permettra alors de mettre en place un service de sauvegarde d'état (persistance) et de récupération de cette sauvegarde pour reprendre les workflows là où ils s'étaient arrêtés.

Image non disponible



Un autre avantage insoupçonné de la persistance est d'améliorer les performances de votre application. En effet, imaginez un workflow comme une chaine d'usine sur laquelle vous déposer un matériel et celui-ci est transformé le long du process. Ce matériel est en .Net, un objet et cet objet prend de la place en mémoire. Vous aurez alors probablement à lancer des centaines d'objets au même moment et la quantité de mémoire utilisée ne fera alors qu'augmenter. Dans le cas d'un workflow sequentiel ininterrompu, vous ne pouvez pas faire grand chose mais dans le cas où celui-ci passe en mode d'attente à un moment ou un autre, il est possible durant ce délai d'attente, de décharger cet objet de la mémoire et de le sérialiser en base de données pour ne le désérialiser qu'au moment où vous aurez besoin de l'utiliser de nouveau.

2. Préparation

2.1. Contexte

Pour nous concentrer sur la persistance et uniquement la persistance, nous prendrons en exemple un très très simple workflow séquentiel executant différentes tâches les unes après les autres sans contraintes externes comme un EventListener. Il s'agira d'un workflow de cuisson, prenant un oeuf fermier ou non, et définissant un état cuit ou non cuit.
Voici le schéma de notre workflow.

Image non disponible

Nous avons un délai d'une minute (délai nous permettant dans le cadre de cet article, de faire crasher l'application afin d'assister à la persistance) ainsi que deux codeActivity, affichant des messages dans la console afin de vérifier à quelle étape du workflow nous nous trouvons.

Voici son code complet

 
Sélectionnez
public sealed partial class monWorkflow : SequentialWorkflowActivity
{
    private OeufALaCoque oeuf;

    public OeufALaCoque Oeuf
    {
        get { return oeuf; }
        set { oeuf = value; }
    }

    public monWorkflow()
    {
        InitializeComponent();
    }

    private void codeDebut_ExecuteCode(object sender, EventArgs e)
    {
        Console.WriteLine("Cuisson démarrée");
        oeuf.Cuit = true;
    }

    private void codeFin_ExecuteCode(object sender, EventArgs e)
    {
        Console.WriteLine("Cuisson terminée");
        Console.WriteLine((oeuf.Cuit) ? "Oeuf cuit" : "Oeuf non cuit");
        Console.WriteLine("Oeuf fermier? {0}", (oeuf.Fermier) ? "oui" : "non");
    }
}

2.2. Base de données

Le cas le plus simple d'utilisation de persistance (et aussi celui conseillé par Microsoft), consiste en l'utilisation d'une base de données SQL Serveur, dans lequel nous créerons des tables qui seront utilisées pour stocker les données persistées.
Bien entendu il est possible de persister vos données dans un autre SGBD ou encore simplement dans des fichiers, mais dans ces cas là, vous devrez vous-même développer votre service de persistance (voir le dernier chapitre de cet article). Si vous êtes pressés ou que tout simplement, vous souhaitez utiliser les outils que met Microsoft à votre disposition alors vous pouvez utiliser le SqlPersistanceService qui consiste en un service déjà prêt à être utilisé et qui ne nécessite que l'éxecution de deux petits scripts SQL afin de préparer la base de données.
Les deux scripts qui nous intéressent sont SqlPersistenceService_Schema.sql (pour les tables) et SqlPersistenceService_Logic.sql (pour les procédures stockées) qui se trouvent dans le répertoire C:\Windows\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL\

Exécutez ces deux scripts dans votre serveur de base de données MS SQL Serveur et vous devriez alors obtenir deux tables et les procédures stockées relatives :

Image non disponible

La table la plus importante est la table InstanceState. C'est dans celle-ci que se trouveront les informations principales de vos instances qui ont été persistées. Vous y trouverez donc un GUID représentant chaque instance, son statut (running, suspended, terminated ou completed) ou encore sa sérialisation complète (state), ainsi que quelques informations supplémentaires sur le moment de la persistance.
La table CompletedScope ne contiendra pas comme pourrait le faire croire son nom, la liste des instances finies. Elle sera bien souvent vide selon le type de workflow que vous créérez car elle ne sert qu'à stocker l'état des transactions à l'intérieur des workflows (voir les activités Compensatable).

Voici un exemple d'une instance de notre workflow persistée en base:

Image non disponible

Maintenant que tout est prêt, nous allons voir comment l'utiliser sérieusement au sein de nos applications.

3. Persister un workflow

Revoyons rapidement comment nous avons appris avec les articles précédents à instancier un nouveau workflow et lui passer un paramètre.

Trois petites lignes suffisent avec lesquelles, nous créeons un dictionnaire de données qui prend un object de type OeufALaCoque avec une clé nommée "Oeuf". Ce nom est le nom de la propriété publique de notre classe de workflow (voir chapitre 2.1).
Ensuite nous créeons une nouvelle instance à l'aide du runtime WF, en lui passant le nom du workflow que l'on veut créer et les paramètres que l'on veut transmettre. Enfin, nous démarrons l'instance.

 
Sélectionnez
Dictionary<string, object> dic = new Dictionary<string, object> {{"Oeuf", new OeufALaCoque(){Fermier=true}}};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof (DVP_WF_Persistance.monWorkflow), dic);
instance.Start();

Maintenant que vous avons de quoi faire tourner un workflow, nous allons devoir mettre en place un mécanisme de sauvegarde régulier de notre workflow. Ce mécanisme consiste en un service (définition: application ou code, tournant en arrière plan et de façon continue, durant tout le temps de vie d'une autre application, ici, notre runtime de workflow).
Ce mécanisme, vous pouvez soit le créer de toute pièce (voir le chapitre 5), ou alors utiliser un service prêt-à-l'emploi: le SqlWorkflowPersistenceService. Ce service est une classe qui ne requiert qu'une base de données et un ou deux réglages.

Pour le créer ou l'utiliser, il existe deux manières. La manière déclarative, qui consiste à l'utilisation de façon claire dans le code:

 
Sélectionnez
using System.Workflow.Runtime.Hosting;
...
SqlWorkflowPersistenceService stateservice =
                    new SqlWorkflowPersistenceService(
                        "Data Source=localhost;Initial Catalog=Developpez;Integrated Security=True", true,
                        new TimeSpan(0, 1, 0), new TimeSpan(0, 0, 30));

workflowRuntime.AddService(stateservice);

Code avec lequel, vous créez un service, en lui passant en paramètre une chaine de connexion pointant vers la base de données où sont stockées les tables de persistances. Vous passez ensuite un paramètre qui définit si le service cherche à décharger automatiquement les workflows qui sont innocupés (idle) afin de libérer de la mémoire, et au final, vous ajoutez deux paramètres, définissant respectivement la durée pour garder un workflow pour son propriétaire (cas où plusieurs applications utilisent les même tables de persistance) et enfin le délai entre chaque "sauvegarde" du service de persistance.

Enfin, nous ajoutons ce service au runtime workflow avant que celui-ci ne soit démarré. Il est impossible d'ajouter un service à un moteur workflow déjà lancé.


Il existe un second moyen de déclarer et configurer un service de persistance. Il s'agit du fichier de configuration

 
Sélectionnez
<WorkflowRuntime Name="SampleApplication" UnloadOnIdle="true">
	<Services>
		<add type="System.Workflow.Runtime.Hosting.SqlStatePersistenceService, System.Workflow.Runtime, 
		     Version=3.0.00000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
			 ConnectionString="Data Source=localhost;Initial Catalog=Developpez;Integrated Security=True"  
			 UnloadOnIdle="true" LoadIntervalSeconds="30"/>
	</Services>
</WorkflowRuntime>

Ce qui revient exactement au même que la méthode déclarative. Cela vous apporte l'avantage de pouvoir modifier le comportement du service sans avoir à recompiler à chaque fois votre application.

Que se passe-t-il s'il la persistance se fait toutes les 30 secondes et que pendant ces 30 secondes, une donnée du workflow est mis à jour et que l'application crash juste ensuite. Cette donnée sera-t-elle sauvegardée? La réponse est "Non". Comment y remedier? On peut simplement limiter ce cas au minimum en réduisant le temps de persistance LoadInterval au minimum (une seconde par exemple). Et bien non, ca corrigerait ce problème mais en entrainerait d'autres. En effet, cela signifierait que pour chaque instance, chaque seconde, plusieurs reqûetes sont faites sur la base de données, entrainant très rapidement, une surcharge processeur, ainsi qu'une surcharge réseau et éventuellement un bouchonnement du serveur SQL. Pensez donc à trouver un bon compromis pour ce délai, selon vos besoins et surtout selon la criticité des problèmes qu'il pourrait entrainer par rapport au risque de perdre une donnée.

Je vous donne le code de la classe OeufALaCoque avant de compiler votre projet et l'éxecuter.

 
Sélectionnez

public class OeufALaCoque
{
    bool _cuit;

    public bool Cuit
    {
        get { return _cuit; }
        set { _cuit = value; }
    }

    private bool fermier;

    public bool Fermier
    {
        get { return fermier; }
        set { fermier = value; }
    }

}

Rapidement, le service de persistance nous crie dessus et nous signale une exception:

Image non disponible

Le message est clair, notre classe n'est pas tagguée comme serialisable et la persistance ne peut se faire. Si vous réflechissez deux secondes, cela doit vous paraitre tout à fait évident. En effet, la persistance n'est rien d'autre que le mécanisme de sérialisation/désérialisation d'un objet, et se fait, dans notre cas, dans une base de données.
Il faut donc que le workflow et les objets qu'il contient, soient tous, sans exception, serialisables.

Ajoutez donc l'attribut [Serializable] sur votre classe et en toute logique, votre workflow devrait se dérouler parfaitement.

Vous pouvez, pour vérifier que la persistance fonctionne, lancer le workflow et profiter de l'éxecution de l'activité Délai pour couper brutalement votre application. Vous alors vérifier qu'en base se trouve bien les informations de persistance de votre workflow.
Pour rappel, il y aura une ligne par instance de workflow, et donc autant de lignes que vous aurez lancé d'instances et qui auront eu le temps de persister au moins une fois.

Image non disponible

4. Récupérer un workflow persisté

Maintenant, que nous avons vu comment persister nos informations en base, nous allons voir comment il est possible de récupérer les instances et continuer leur éxécution.

Le déchargement des instances en base était simple et vous allez voir que le rechargement l'est tout autant. En effet, il est possible via des méthodes appartenant au service de persistance, d'intérroger les instances persistées et de les contrôler. Voici un exemple simple.

 
Sélectionnez
SqlWorkflowPersistenceService persistance =
                            (SqlWorkflowPersistenceService)
                            workflowRuntime.GetService(typeof (SqlWorkflowPersistenceService));
IEnumerable<SqlPersistenceWorkflowInstanceDescription> instances = persistance.GetAllWorkflows();
foreach(SqlPersistenceWorkflowInstanceDescription  insDesc  in instances)
{
    // votre code sur les instances
}

On se sert du service de persistances pour récupérer les descriptions des instances persistées. A partir de là, il est possible d'afficher des informations sur celles-ci

 
Sélectionnez
Console.WriteLine("Instance n°{0} est en statut: {1}", insDesc.WorkflowInstanceId, insDesc.Status);

Ou de relancer une instance:

 
Sélectionnez
workflowRuntime.GetWorkflow(insDesc.WorkflowInstanceId).Load();

Pour finir, et pour justifier le fait de relancer une instance particulière, il est intéressant de savoir que vous auriez pu décharger "manuellement" une instance en appelant sa méthode Unload et en stockant au même moment son GUID dans une autre table de la base de données. Ceci vous permet de contrôler les instances persistées et savoir plus facilement à quoi elles correspondent (si vous avez pris la peine de stocker des informations pertinentes reliées au GUID sauvegardé).

Voilà, c'est tout ce qu'il faut savoir pour mettre en place rapidement et simplement un service de persistance au sein de Workflow Foundation.

5. Utilisez des versions différentes de votre workflow en même temps

Pour l'instant, nous nous sommes contentés de persister des instances d'une même version de notre workflow. Cependant, que se passe-t-il lorsque notre définition du workflow change ou bien lorsque la version de l'assembly qui contient le workflow change ?

A priori, tout se passera bien SAUF si des workflows en version 1 ont été persistés ! Avant d'aller plus loin, reprenons depuis le début avec notre workflow en version 1 et version 2.

Première étape est de s'assurer que la classe représentant notre workflow se trouve bien dans un projet de type librairie.

Image non disponible

Ensuite, reprenons notre workflow dans sa version 1 :

Image non disponible

Avec notre projet " DeveloppezPersistanceCore " en version 1.0.0.0. Ce qui, après compilation, conduira à une assembly " DeveloppezPersistanceCore.dll " en version 1.0.0.0.

Image non disponible

Lançons notre application et générons quelques œufs, donc quelques workflows, et fermons l'application avec que ces derniers aient fini leur cycle de vie. Nous aurons donc en base de données des entrées de ce style :

Image non disponible

Maintenant, procédons au changement de version de l'assembly de notre workflow. Pour cela, il faut retourner dans les propriétés de notre projet de type librairie (" DeveloppezPersistanceCore ") pour changer la version de 1.0.0.0 à 2.0.0.0.

Image non disponible

Et modifions notre workflow en ajoutant une activité " delay " supplémentaire. Ce qui nous donne :

Image non disponible

En recompilant notre solution, l'assembly " DeveloppezPersistanceCore.dll " sera recompilée en version 2.0.0.0.

Lorsque nous allons lancer notre application, les workflows générés auront comme version 2.0.0.0 et si nous tentons de relancer des workflows persistés en version 1.0.0.0, nous allons obtenir une exception du type " System.IndexOutOfRangeException " avec le message d'erreur suivant :

"Index was outside the bounds of the array."

La raison est que notre workflow persisté a été sérialisé et lorsque vous tentez de le récupérer via la méthode " GetInstance ", il est impossible d'accéder à l'assembly " DeveloppezPersistanceCore.dll " en version 1.0.0.0. Et d'ailleurs, le dé sérialisation ne peut qu'échouer étant donné que la classe qui représente notre workflow a changé avec l'ajout d'une activité " delay ".

La solution serait donc de donner à disposition aussi bien la version courante de notre assembly " DeveloppezPersistanceCore.dll " que les versions précédentes. Pour cela, il n'y a qu'une seule solution, c'est le " versioning " d'assemblies.

Première étape et pré-requis : signer son assembly en donnant un nom fort

Pour donner un nom fort à son assembly, il suffit d'aller dans les propriétés de notre projet librairie. Rendez-vous dans l'onget " Signing ".

Image non disponible

Et donnez le nom que vous désirez à votre assembly :

Image non disponible

Seconde étape : Mettre à disposition chaque version de votre assembly

Lorsque votre application tourne et qu'elle a besoin de dé sérialiser un workflow version 1.0.0.0, 2.0.0.0 ou x.0.0.0, il faut donner accès à l'assembly correspondante pour que la dé sérialisation fonctionne. Pour cela, on va par exemple mettre chaque version de notre assembly dans un sous répertoire " Assemblies " de notre exécutable. Ainsi, on pourrait avoir quelque chose similaire à l'écran suivant :

Image non disponible

Evidemment, j'ai décidé de renommer les anciennes versions de l'assembly et des les placer dans un sous répertoire nommé " Assemblies " mais vous êtes tout à fait libre de placer votre assemblies où vous voulez et des nommer comme vous le voulez.

Troisième étape : Référencer les anciennes versions de l'assembly dans votre projet

Pour l'instant, nous avons notre application qui tourne avec l'assembly " DeveloppezPeristanceCore.dll " en version 3.0.0.0. S'il faut dé sérialiser un workflow en version 1.0.0.0 ou 2.0.0.0, les assemblies " DeveloppezPersistanceCore_V1_0_0_0.dll " et " DeveloppezPersistanceCore_V2_0_0_0.dll " ne seront pas appelées automatiquement.

C'est au niveau du fichier de configuration que l'on va pouvoir spécifier l'emplacement de l'assembly à charger dans le cas où c'est une ancienne version à utiliser. Par exemple pour les versions 1.0.0.0 et 2.0.0.0, on aura :

 
Sélectionnez
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="DeveloppezPersistanceCore"
                        publicKeyToken="a899c98ba2437d3c"
                        culture="neutral" />
      <codeBase version="1.0.0.0" href="Assemblies/DeveloppezPersistanceCore_V1_0_0_0.dll"/>
    </dependentAssembly>
    <dependentAssembly>
      <assemblyIdentity name="DeveloppezPersistanceCore"
                        publicKeyToken="a899c98ba2437d3c"
                        culture="neutral" />
      <codeBase version="2.0.0.0" href="Assemblies/DeveloppezPersistanceCore_V2_0_0_0.dll"/>
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Pour connaître le " publicKeyToken " de vos assembly, il existe un outil nommé " sn.exe " qui vous permettra de connaître cette information en le lançant de la manière suivante dans votre invite de commande :

sn -T DeveloppezPersistanceCore.dll

Pour plus d'information sur cet outil, je vous invite à vous rendre sur la page Microsoft MSDN dédiée à l'outil sn.exe.

6. Pour aller plus loin

Il se peut que ce service de persistance ne vous suffise pas et que vous aimeriez bien agir d'une autre manière, plus complète, pour la persistance de vos workflows. La solution se trouve alors dans le développement de votre propre service de persistance. La solution qui sera utilisée, sera de créer sa propre classe héritant de WorkflowPersistenceService et de redéfinir les méthodes qui nous intéressent particulièrement, à savoir SaveWorkflowInstanceState et LoadWorkflowInstanceState.

Commencez par créer une nouvelle classe nommée monServiceDePersistanceXML. Faites le hériter de WorkflowPersistenceService et implémenter ses membres.

Image non disponible

Vous obtenez le code suivant:

 
Sélectionnez
public class monServiceDePersistanceXML : WorkflowPersistenceService
{
    protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
    {
        throw new System.NotImplementedException();
    }

    protected override void UnlockWorkflowInstanceState(Activity rootActivity)
    {
        throw new System.NotImplementedException();
    }

    protected override Activity LoadWorkflowInstanceState(Guid instanceId)
    {
        throw new System.NotImplementedException();
    }

    protected override void SaveCompletedContextActivity(Activity activity)
    {
        throw new System.NotImplementedException();
    }

    protected override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
    {
        throw new System.NotImplementedException();
    }

    protected override bool UnloadOnIdle(Activity activity)
    {
        throw new System.NotImplementedException();
    }
}

Il reste donc tout à faire! Commençons par créer nos méthodes de sérialisation et désérialisation XML.

Créez les méthodes Serialize et Deserialize comme suit:

 
Sélectionnez

private void Serialize(byte[] activite, Guid id)
{
    var seriaz = new XmlSerializer(activite.GetType());
    TextWriter writer = new StreamWriter(String.Format("{0}.xml", id));
    seriaz.Serialize(writer, activite);
    writer.Close();
}

private byte[] Deserialize(Guid id)
{
    byte[] wf = null;
    var seriaz = new XmlSerializer(typeof(byte[]));
    TextReader reader =
        new StreamReader(String.Format("{0}.xml", id));
    wf = (byte[])seriaz.Deserialize(reader);
    reader.Close();
    return wf;
}

Il s'agit ici d'une simple sérialisation dans un format XML et j'ai volontairement choisi d'y stocker un tableau de bytes, perdant une partie de l'avantage XML, uniquement dans le but de vous montrer l'intérêt des méthodes RestoreFromDefaultSerializedForm et GetDefaultSerializedForm appartenant directement au service de persistance par défaut (WorkFlowPersistenceService).
Passons maintenant aux méthodes suivantes.

La première chose que l'on souhaite faire, c'est utiliser la bonne méthode, qui nous permettra de récuperer notre instance et agir sur cette dernière. La méthode qui nous intéresse est tout simplement SaveWorkflowInstanceState, qui est LA méthode, appelée à chaque point de persistence (=validation d'un état).

 
Sélectionnez
protected override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
{
    var guid = (Guid) rootActivity.GetValue(Activity.ActivityContextGuidProperty);
    Serialize(GetDefaultSerializedForm(rootActivity), guid);
}

C'est assez simple, il nous faut, pour notre méthode de sérialisation, l'objet à sérialiser sous forme de tableau de bytes et l'identifiant unique de cette instance. Cette id, nous le savons, réprésente de façon unique une instance et nous permettra de la recharger par la suite.
Concernant la transformation en tableau de bytes, nous utilisons la méthode GetDefaultSerializedForm dont je vous parlais plus haut. Cette forme de stockage est le plus fiable et peut être utilisé pour de la sérialisation en binaire dans des fichiers texte ou simplement dans une base de donnée quelconque.

A l'inverse de cette méthode, nous avons la méthode LoadWorkflowInstanceState qui est appelé lorsqu'il est nécessaire de recharger une instance avant de la rendre au runtime de workflow pour que celui-ci continue son éxécution.

 
Sélectionnez
protected override Activity LoadWorkflowInstanceState(Guid instanceId)
{
    return RestoreFromDefaultSerializedForm(Deserialize(instanceId), null);
}

Cette fois-ci, nous désérialisons notre tableau de bytes avant de le retransformer en Activity pour enfin retourner ce nouvel objet à notre runtime.

Les méthodes SaveCompletedContextActivity et LoadCompletedContextActivity suivent la même logique et auront le même coeur de méthode.

Nous ignorons volontairement les méthodes UnlockWorkflowInstanceState et UnloadOnIdle car elles ne sont pas requises pour de la persistance simple.

Et c'est tout! Avec ces quelques lignes, nous avons créé notre propre service de persistence et cela nous permet de nous passer de base de données et de profiter de cette mécanique pour rendre notre application plus fiable (même les performances ne seront pas les mêmes).

7. Conclusion

Il n'y a pas grand chose à dire sur la persistance de Workflow Foundation si ce n'est qu'elle est requise pour quasiment tous les projets sérieux et que sa mise en place est extrêmement simple. N'hésitez pas à utiliser le service de persistance SQL déjà tout prêt, il est rodé et marche parfaitement bien.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2008 Louis-Guillaume Morand et Jérôme Lambert. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.