Après mon précédent article qui attaque les contraintes par la fasse Nord de l’Everest… passons à la seconde possibilité offerte par WF4 pour valider une activité : la metadata. Je vous en ai déjà toucher un ou deux mots. La metadata dans WF4 est un élément “complexe” car très puissant entre les mains d’un développeur WF4… par contre pour une jeune padawan WF4… c'est le côté obscure du Workflow.

… donc on fais attention, et on suis le guide… pour ne pas finir mal…

Contrairement à la collection Constraints qui est alimentée lors de la construction de l’activité, la metadata est un élément qui est rafraichi sur demande du designer (après une modification sur l’activité, ou son environnement proche par exemple).

L’autre grande différence réside dans le fais que l’on n’inclut pas de logique de validation dans la metadata, mais le résultat de la validation. Cette validation, c’est à vous de la faire à chaque demande de la metadata. On peut envisager alors la metadata comme un conteneur volatile que vous êtes chargé de rafraichir dans la méthode CacheMetadata de votre activité.

Si l’état de vos arguments ne vous conviens donc pas, c’est à vous de faire remonter une erreur. Ou un warning : les ronds rouges, c’est monotone. Donc penser au petit triangle jaune du warning si votre validation n’est là qu’à titre indicatif et donc sans réel blocage du workflow.

Pour que les choses soient claires, j’ai écris ici un équivalent de mon précédent exemple.

/// <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()
    {
    }

    #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"

    protected override void CacheMetadata(CodeActivityMetadata metadata)
    {
        // Pour le momeent on en touche pas à la base
        base.CacheMetadata(metadata);

        if (this.m_Program == null)
        {
            metadata.AddValidationError(
                new ValidationError(
                    "La propriété [Program] ne dois pas être vide.", 
                    false, 
                    "Program"));
        }

        if (this.m_Arguments == null)
        {
            metadata.AddValidationError(
                new ValidationError(
                    "La propriété [Arguments] ne dois pas être vide.",
                    false, 
                    "Arguments"));
        }
    }

    /// <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

}

Comme on peut le voir ici, le code est plus “léger”.