Avec Workflow Foundation 4, la persistance de Workflow est devenue un régale. On code quelques lignes et en un temps record on se retrouve avec une instance de workflow qui persiste en base. Oui mais (oui encore mon “Oui mais”) faut il encore comprendre ce que l’on fait. Tout développeur débutant avec WF4 a dut tombé nez à nez au moins un fois avec la page suivant :

A Developer's Introduction to Windows Workflow Foundation (WF) in .NET 4

Si vous ne l’avez pas encore consulté, c’est le moment car : utiliser WF4 sans passer par cette page c’est vraiment dommage. Cette page contient justement un petit bou de code pour cré un InstanceStore de type SqlWorkflowInstanceStore.

WorkflowApplication application = new WorkflowApplication(activity);

InstanceStore instanceStore = new SqlWorkflowInstanceStore(
    @"Data Source=.\SQLEXPRESS;Integrated Security=True");

InstanceView view = instanceStore.Execute(
    instanceStore.CreateInstanceHandle(), 
    new CreateWorkflowOwnerCommand(),
    TimeSpan.FromSeconds(30));

instanceStore.DefaultInstanceOwner = view.InstanceOwner;

application.InstanceStore = instanceStore;

Le vrai souci avec ce code c’est qu’il a effectivement été vu par pas mal de monde et utilisé tel quel sans se demander ce qu’il faisait vraiment.

Non, non, non, c’est sur la MSDN, dont ça marche un point c’est tout! On copie et on colle.

Si seulement la vie pouvait être aussi simple ;-). En fait, en utilisant ce code vous prenez la responsabilité de gérer manuellement le mécanisme de verrouillage des instances de workflow persistés ceci peut effectivement être utile si vous avez décidé d’utiliser une instance de SqlWorkflowInstanceStore pour plusieurs instances de WorkflowApplciation. Car par défaut se scénario ne s’exécute pas correctement sans instance de CreateWorkflowOwnerCommand. Seule véritable ombre à ceci : votre instance de workflow aura bien un propriétaire qui se chargera de la verrouiller en base, mais personne pour la déverrouiller….

C’est alors qu’intervient le DeleteWorkflowOwnerCommand. Comme sont nom l’indique, il est chargé de retiré le verrou que le CreateWorkflowOwnerCommand va mettre en place. Donc si on veut utiliser le code présenté plus haut, il faut le modifier comme ceci pour garder de coté une variable contenant l’InstanceHandle du store:

WorkflowApplication application = new WorkflowApplication(activity);

InstanceStore instanceStore = new SqlWorkflowInstanceStore(
    @"Data Source=.\SQLEXPRESS;Integrated Security=True");

InstanceHandle instanceHandle = instanceStore.CreateInstanceHandle();

InstanceView view = instanceStore.Execute(
    instanceHandle,
    new CreateWorkflowOwnerCommand(),
    TimeSpan.FromSeconds(30));

instanceStore.DefaultInstanceOwner = view.InstanceOwner;

application.InstanceStore = instanceStore;

Et quand vous n’avez plus besoin de votre store (au pire quand votre application prend fin) :

instanceStore.Execute(
    instanceHandle,
    new DeleteWorkflowOwnerCommand(),
    TimeSpan.FromSeconds(30));
Sans ce code vos instances seront verrouillées. Pas cool :(

Voila, le tour est joué, vous avez un store sql qui marche correctement et vos instances qui y entrent et sortent à volonté.

Oui Mais…

Je ne voudrais pas abuser, mais avez vous vraiment besoin de n’avoir qu’une instance de SqlWorkflowInstanceStore pour vos multiples instance de WorkflowApplication?

Dans 95% des cas je dirais bien : NON (et encore je ne vois pas trop où je trouve les 5% restants). Car plusieurs instances de SqlWorkflowInstanceStore peuvent être connectés à la même base de données sans soucis ni adaptation particulière. Alors pourquoi prendre le risque de verrouiller accidentellement des instances de workflow (on n’est jamais à l’abri d’une fermeture inopinée de l’application sans libération des verrous)?

La bonne pratique voudrait donc conclure par l’utilisation d’une instance de SqlWorkflowInstanceStore par WorkflowApplication.

D’où un code franchement Light :

WorkflowApplication application = new WorkflowApplication(activity);

application.InstanceStore = new SqlWorkflowInstanceStore(
    @"Data Source=.\SQLEXPRESS;Integrated Security=True");

Pour plus d’information sur le paramétrage du store Sql, je vous encourage à aller voir cette autre page de la MSDN :

Procédure : activer la persistance SQL pour les workflows et les services de workflow

Et pour l’instanciation de store Sql les remarques de Maurice De Beijer sur sur blog. Malheureusement son article n’a pas forcément été bien assimilé car on trouve encore pas mal de monde sur le forum MSDN US qui grogne après des instances de workflow verrouillées.

J’espère au moins que cette article si évitera la même débâcle chez les francophones. Si vous voulez donc limiter la casse, retenez ceci : 1 WorkflowApplication pour 1 SqlWorkflowInstanceStore