De WF3 à WF4 pas mal de choses on été changées pour faciliter la vie des développeurs, mais certain points peuvent sembler obscures… comme les contraintes.

Pour vous guider, je me lance dans une série de deux articles. Ils présenterons deux approches possibles pour mettre en place des contraintes sur une activité.

Petit rappela avant de se lancer :

L’objectif des contraintes est de forcer l’utilisateur de vos activités à saisir leurs propriétés. En gros il s’agit d’une validation de l’utilisation de votre activité.

 

Ce premier article est dédié à la présentation de la collection Constraints. L’utilisation classique de celle-ci étant décrite par le fameux “A Developer's Introduction to Windows Workflow Foundation (WF4) in .NET 4 Beta 2” de Matt Milner. Plutôt que de faire une reprise maladroite, je m’attaque ici à un cas un peu plus complexe : Ajouter plusieurs contraintes. Cela peut sembler idiot, mais comprendre le code de l’article base et le transposer pour ce cas n’est pas forcement des plus simple pour un nouveau venu dans WF.

Pour commencer plusieurs questions doivent trouver réponse :

Où se place la validation?

-> Dans le constructeur de l’activité. La classe de base contient une collection de contraintes : base.Constraints.

Comment avoir une validation par activité?

-> en instanciant un objet Constraint<T> avec un DelegateInArgument<T> (avec T étant le type de votre activité) pour chaque propriété à valider

Comment lui indiquer nos propriété à valider? La logique de validation? Le message d’erreur?

-> Votre Constraint<T> a un Handler qui va contenir le nom de la propriété, le message d’erreur à afficher et la logique

Voici donc un petit exemple d’activité qui répond à ces quelques questions.

Note : Cette action permet de lancer un program en lui fournissant des arguments.

/// <summary>
/// Activité qui permet d'executer un program
/// </summary>
public class ExecuterUnProgram : CodeActivity
{
    #region "Déclarations"

    private InArgument<String> m_Program;
    private InArgument<String> m_Arguments;

    #endregion

    #region "Constructeur / destructeur"

    public ExecuterUnProgram()
    {
        // Context pour la validation
        DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext>();

        // ------------------------------------------------------------------
        // Activité de validation du program
        DelegateInArgument<ExecuterUnProgram> activityProgram = new DelegateInArgument<ExecuterUnProgram> { Name = "argumentP" };
        // Contrainte
        Constraint<ExecuterUnProgram> consProgram = new Constraint<ExecuterUnProgram>
        {
            Body = new ActivityAction<ExecuterUnProgram, ValidationContext>
            {
                Argument1 = activityProgram,
                Argument2 = validationContext,
                Handler = new AssertValidation
                {
                    // Message affiché dans le designer de WorkFlow
                    Message = "La propriété [Program] ne dois pas être vide.",
                    // Propériété à mettre en évidence dans le designer
                    PropertyName = "Program",
                    Assertion = new InArgument<Boolean>(
                        (e) => activityProgram.Get(e).m_Program != null)
                }
            }
        };
        // Ajout de la contrainte
        base.Constraints.Add(consProgram);

        // ------------------------------------------------------------------
        // Activité de validation des arguments
        DelegateInArgument<ExecuterUnProgram> activityArgument = new DelegateInArgument<ExecuterUnProgram> { Name = "argumentA" };
        // Contrainte
        Constraint<ExecuterUnProgram> consArguments = new Constraint<ExecuterUnProgram>
        {
            Body = new ActivityAction<ExecuterUnProgram, ValidationContext>
            {
                Argument1 = activityArgument,
                Argument2 = validationContext,
                Handler = new AssertValidation
                {
                    // Message affiché dans le designer de WorkFlow
                    Message = "La propriété [Arguments] ne dois pas être vide.",
                    // Propériété à mettre en évidence dans le designer
                    PropertyName = "Arguments",
                    Assertion = new InArgument<Boolean>(
                        (e) => activityArgument.Get(e).m_Arguments != null)
                }
            }
        };
        // Ajout de la contrainte
        base.Constraints.Add(consArguments);
    }

    #endregion

    #region "Propriétés"

    /// <summary>
    /// Program à executer
    /// </summary>
    public InArgument<String> Program
    {
        get { return this.m_Program; }
        set { this.m_Program = value; }
    }        

    /// <summary>
    /// Arguments du Program à executer
    /// </summary>
    public InArgument<String> Arguments
    {
        get { return m_Arguments; }
        set { m_Arguments = value; }
    }

    #endregion

    #region "Méthodes"

    /// <summary>
    /// Action  executée par l'acitivité
    /// </summary>
    /// <param name="context"></param>
    protected override void Execute(CodeActivityContext context)
    {
        Process.Start(this.m_Program.Get(context), this.m_Arguments.Get(context));
    }

    #endregion

}