“Les extensions dans Workflow Foundation” : voila un sujet qui a fait couler beaucoup d’ancre dans WF3 tellement le mécanisme pouvait sembler contraignant. Avec WF4, les extensions sont devenues d’une simplicité déconcertante. Mais comme je l’ai déjà dit avec WF4 : simple ne veut pas dire qu’il n’y a pas de précautions à prendre.

Premier point, toute classe peut devenir une extension. Même si il est conseiller de coder une interface pour son extension, ce n’est pas obligatoire.

Pour mon exemple j’ai codé une extension simple qui rend disponible une propriété Text de type String :

class MyExtension
{
    public MyExtension()
    {
        this.Text = DateTime.Now.ToString();
    }

    public String Text { get; set; }
}

Comme dans WF3 les extension s’ajoutent avant l’exécution du workflow :

static void Main(string[] args)
{
    WorkflowInvoker wi = new WorkflowInvoker(new Workflow1());

    wi.Extensions.Add(new MyExtension());
    wi.Invoke();
    Console.Read();
}

Ensuite pour retrouver l’extension dans ses activités, il suffit d’interroger le contexte en lui indiquant le type recherché. Si votre extension dispose d’une interface, celle-ci peut être utilisée en lieu et place du type de la classe.

Voici donc une première activité qui va modifier la propriété Text de l’extension :

public sealed class SetMyExtensionText : CodeActivity
{
    public InArgument<string> Text { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        MyExtension e = context.GetExtension<MyExtension>();
        if (e != null)
        {
            String text = context.GetValue(this.Text);
            e.Text = text;
        }
    }
}

Et une seconde activité qui va consulter la propriété Text de l’extension :

public sealed class GetMyExtensionText : CodeActivity<String>
{
    protected override string Execute(CodeActivityContext context)
    {
        MyExtension e = context.GetExtension<MyExtension>();
        if (e != null)
        {
            return e.Text;
        }
        else
        {
            return String.Empty;
        }
    }
}
Pour mon exemple, j’ai réalisé le workflow suivante :Workflow_Extension

Ce workflow contient une variable “text” qui sert de retour aux activités GetMyExtensionText. J’ai aussi affecté une String “Mon nouveau text” à l’argument Text de mon activité SetMyExtensionText.

A l’exécution on obtient donc le message suivante :

Workflow_Extension_console

Simple, non?

Oui mais attention : la liste d’extensions ne lèvera pas d’erreur si par mégarde on y introduit plusieurs instances du même type (ou implémentant la même interface). Donc prudence, et utilisez toujours un type clairement identifiable.

Si vous vous demandez quel peut être l’intérêt des extensions, il faut penser à un scénario où la définition du workflow doit être unique mais l’extension doit être de type déterminé dynamique au moment de l’exécution. Le type répondant à une interface connue du workflow, on peut manipuler une extension dont le comportement peut être totalement différent d’une exécution à l’autre.

Intéressant, non?