Quand on découvre WF4, on ne peut que succomber au charme du WorkflowInvoker. Il faut dire qu’après avoir connu WF3, il s’agit d’une petite révolution culturelle. Mais pourquoi donc?

  • WorkflowInvoker, c’est la fin du WorkflowRuntime.
  • WorkflowInvoker c’est donc aussi la fin du besoin d’utiliser un Singleton de type WorkflowRuntime.
  • Et donc : plus besoin de codes annexes pour la gestion du WorkflowRuntime (notemment lors de la fermeture de l’applciation).

Sympa tout cela! Et en plus il ne nous faut qu’une ligne de code pour lancer un Workflow :

WorkflowInvoker.Invoke(new MyWorkflow());

Oui, mais… (et oui encore un mais. Je ne peux pas m’en empêcher..)

  • Qui vas  nous permettre d’intégrer nos services de persistance et d’avoir des informations sur l’état de notre Workflow?
  • Qui vas nous indiquer si un Workflow s’est terminé prématurément?
  • Et pour lancer un Workflow en asynchrone?

Si vous vous posez toutes ces question, WorkflowApplication est votre nouveau héro ;)

Pour utiliser WorkflowApplication, il n’y a pas de mystère : on instancie un WorkflowApplication en lui passant une instance de notre workflow et d’éventuels arguments. Ensuite on lance la méthode Run().

Par défaut

WorkflowApplication workflowApplication = new WorkflowApplication(new MyWorkflow()); 

AutoResetEvent autoResetEvent = new AutoResetEvent(false); 

workflowApplication.Completed = c => 
{  
    // Traiter le 
    switch (e.CompletionState) 
    {   
         // Traiter les différente raison qui on conduit à la fin de ce Workflow (erreur, interrupetion, fin normale…)  
   } 
    // c.Outputs["..."] 
    autoResetEvent.Set(); 
}; 

workflowApplication.Run(); 

autoResetEvent.WaitOne();

Comme vous pouvez le voir dans ce petit exemple on peut associé un délégué au passage et ainsi avoir une maitrise sur ce qui ce passe ou s’est passé lors de l’exécution du Workflow.

Si on y regarde de plus près dans la MSDN, on se rend compte que le WorkflowApplication n’a pas d’event, mais des propriétés de type Action<T>.

En grand allergique des mots delegate, var,.. etc… , je milite depuis pas mal de temps pour l’utilisation de méthodes et délégués déclarés explicitement. Dans cet ésprit, j’ai cassé les pieds à pas mal de développeurs pour qu’ils s’orientent vers se genre de code. Je ne peux donc pas passé à côté du WorkflowApplication sans vous présenter un code d’avantage orientée “Production”.

Vb

Class MyWorkflowInvoker

    #Region "Déclarations"

    Private Readonly m_AutoResetEvent As AutoResetEvent
    Private Readonly m_WorkflowApplication As WorkflowApplication

    #End Region

    #Region "Constructeur"

    ''' <summary>
    ''' Instanciation de l'invoker
    ''' </summary>
    ''' <param name="workflow"></param>
    Public New(ByVal workflow As Activity)    
        Me.m_AutoResetEvent = New AutoResetEvent(False)
        Me.m_WorkflowApplication = New WorkflowApplication(workflow)
        Me.m_WorkflowApplication.Completed = New Action(Of WorkflowApplicationCompletedEventArgs)(Me.ActionCompleted)
        Me.m_WorkflowApplication.Aborted = New Action(Of WorkflowApplicationAbortedEventArgs)(Me.ActionAborted)
    End

    #End Region

    #Region "Méthodes"

    Public Sub Run()
        Me.m_WorkflowApplication.Run()
        Me.m_AutoResetEvent.WaitOne()
    End Sub

    ''' <summary>
    ''' Workflow terminé
    ''' </summary>
    ''' <param name="e"></param>
    Private Sub ActionCompleted(ByVal e As WorkflowApplicationCompletedEventArgs)
        ' Traiter le 
        Select (e.CompletionState) '...
        
            ' Traiter les différentes raisons qui on conduit à la fin de ce Workflow (erreur, interrupetion, fin normale…)
        
	End Select
        
	Me.m_AutoResetEvent.Set()
    End Sub
    
    ''' <summary>
    ''' Workflow abandonné avant sa fin
    ''' </summary>
    ''' <param name="e"></param>
    Private Sub ActionAborted(ByVal e WorkflowApplicationAbortedEventArgs)

        ' ...

        Me.m_AutoResetEvent.Set()
    End Sub

    #End Region

End Class

C#

class MyWorkflowInvoker
{
    #region "Déclarations"

    private readonly AutoResetEvent m_AutoResetEvent;
    private readonly WorkflowApplication m_WorkflowApplication;

    #endregion

    #region "Constructeur"

    /// <summary>
    /// Instanciation de l'invoker
    /// </summary>
    /// <param name="workflow"></param>
    public MyWorkflowInvoker(Activity workflow)
    {
        this.m_AutoResetEvent = new AutoResetEvent(false);
        this.m_WorkflowApplication = new WorkflowApplication(workflow);
        this.m_WorkflowApplication.Completed = new Action<WorkflowApplicationCompletedEventArgs>(this.ActionCompleted);
        this.m_WorkflowApplication.Aborted = new Action<WorkflowApplicationAbortedEventArgs>(this.ActionAborted);
    }

    #endregion

    #region "Méthodes"

    public void Run()
    {
        this.m_WorkflowApplication.Run();
        this.m_AutoResetEvent.WaitOne();
    }

    /// <summary>
    /// Workflow terminé
    /// </summary>
    /// <param name="e"></param>
    private void ActionCompleted(WorkflowApplicationCompletedEventArgs e)
    {
        // Traiter le 
        switch (e.CompletionState) 
        {
            // Traiter les différente raison qui on conduit à la fin de ce Workflow (erreur, interrupetion, fin normale…)
        }
        
	this.m_AutoResetEvent.Set();
    }
    
    /// <summary>
    /// Workflow abandonné avant sa fin
    /// </summary>
    /// <param name="e"></param>
    private void ActionAborted(WorkflowApplicationAbortedEventArgs e)
    {
        // ...
        this.m_AutoResetEvent.Set();
    }
    #endregion
}

Petit invoker personnalisé qui pourra être utilisé comme ceci :

MyWorkflowInvoker myWorkflowInvoker = new MyWorkflow(new MyWorkflow());
MyWorkflowInvoker.Run;