Partager via


Appel de la validation d'activité

La validation d’activité offre une méthode d’identification et de signalisation des erreurs dans la configuration de toute activité, avant son exécution. La validation a lieu lorsque, dans le Concepteur de Workflow, un workflow est modifié et que l'ensemble des erreurs ou avertissements de validation sont affichés. La validation se produit également au moment de l’exécution lorsqu’un workflow est appelé et si des erreurs de validation se produisent, InvalidWorkflowException est levée par la logique de validation par défaut. Windows Workflow Foundation (WF) fournit la classe ActivityValidationServices qui peut être utilisée par les développeurs d’outils et applications de workflow pour valider explicitement une activité. Cette rubrique décrit comment utiliser la classe ActivityValidationServices pour valider une activité.

Utilisation de la classe ActivityValidationServices

La classe ActivityValidationServices compte deux surcharges Validate, utilisées pour appeler la logique de validation d’une activité. La première surcharge prend l’activité racine à valider et retourne une collection d’erreurs et avertissements de validation. Dans l’exemple suivant, une activité Add personnalisée qui compte deux arguments requis est utilisée.

public sealed class Add : CodeActivity<int>  
{  
    [RequiredArgument]  
    public InArgument<int> Operand1 { get; set; }  
  
    [RequiredArgument]  
    public InArgument<int> Operand2 { get; set; }  
  
    protected override int Execute(CodeActivityContext context)  
    {  
        return Operand1.Get(context) + Operand2.Get(context);  
    }  
}  

L'activité Add est utilisée dans un objet Sequence, mais ses deux arguments requis ne sont pas liés, comme indiqué dans l'exemple suivant :

Variable<int> Operand1 = new Variable<int>{ Default = 10 };  
Variable<int> Operand2 = new Variable<int>{ Default = 15 };  
Variable<int> Result = new Variable<int>();  
  
Activity wf = new Sequence  
{  
    Variables = { Operand1, Operand2, Result },  
    Activities =
    {  
        new Add(),  
        new WriteLine  
        {  
            Text = new InArgument<string>(env => "The result is " + Result.Get(env))  
        }  
    }  
};  

Ce flux de travail peut être validé en appelant Validate. La méthode Validate retourne une collection de l'ensemble des erreurs ou avertissements de validation contenus dans l'activité et tout enfant, comme indiqué dans l'exemple suivant :

ValidationResults results = ActivityValidationServices.Validate(wf);  
  
if (results.Errors.Count == 0 && results.Warnings.Count == 0)  
{  
    Console.WriteLine("No warnings or errors");  
}  
else  
{  
    foreach (ValidationError error in results.Errors)  
    {  
        Console.WriteLine("Error: {0}", error.Message);  
    }  
    foreach (ValidationError warning in results.Warnings)  
    {  
        Console.WriteLine("Warning: {0}", warning.Message);  
    }  
}  

Lorsque la méthode Validate est appelée sur cet exemple de flux de travail, deux erreurs de validation sont retournées.

Erreur : La valeur pour un argument d'activité 'Operand2' requis n'a pas été fournie.
Erreur : La valeur pour un argument d'activité 'Operand1' requis n'a pas été fournie. Si ce workflow était appelé, un InvalidWorkflowException serait levé, comme indiqué dans l'exemple suivant :

try  
{  
    WorkflowInvoker.Invoke(wf);  
}  
catch (Exception ex)  
{  
    Console.WriteLine(ex);  
}  

System.Activities.InvalidWorkflowException :
Les erreurs suivantes ont été rencontrées lors du traitement de l’arborescence de workflow :’Add’ : La valeur pour un argument d’activité ’Operand2’ requis n’a pas été fournie.’Add’ : La valeur pour un argument d’activité ’Operand1’ requis n’a pas été fournie. Pour que cet exemple de workflow soit valide, les deux arguments requis de l’activité Add doivent être liés. Dans l’exemple suivant, les deux arguments requis sont liés aux variables de flux de travail, tout comme la valeur de résultat. Dans cet exemple, l'argument Result est lié, ainsi que les deux arguments requis. L'argument Result ne doit pas forcément être lié et ne provoque pas d'erreur de validation s'il ne l'est pas. Il incombe à l'auteur du workflow de lier l'objet Result, si sa valeur est utilisée ailleurs dans le flux de travail.

new Add  
{  
    Operand1 = Operand1,  
    Operand2 = Operand2,  
    Result = Result  
}  

Validation des arguments requis à l’activité racine

Si l'activité racine d'un workflow possède des arguments, ils ne sont pas liés jusqu'à ce que le workflow soit appelé et les paramètres passés au workflow. Le workflow suivant passe la validation, mais une exception est levée si le workflow est appelé sans passer les arguments requis, comme indiqué dans l’exemple suivant.

Activity wf = new Add();  
  
ValidationResults results = ActivityValidationServices.Validate(wf);  
// results has no errors or warnings, but when the workflow  
// is invoked, an InvalidWorkflowException is thrown.  
try  
{  
    WorkflowInvoker.Invoke(wf);  
}  
catch (Exception ex)  
{  
    Console.WriteLine(ex);  
}  

System.ArgumentException : les paramètres de l'argument de l'activité racine sont incorrects.
Corrigez la définition de workflow ou indiquez des valeurs d’entrée pour corriger ces erreurs :’Add’ : La valeur pour un argument d’activité ’Operand2’ requis n’a pas été fournie.’Add’ : La valeur pour un argument d’activité ’Operand1’ requis n’a pas été fournie. Une fois les arguments appropriés passés, le workflow se termine correctement, comme indiqué dans l’exemple suivant.

Add wf = new Add();  
  
ValidationResults results = ActivityValidationServices.Validate(wf);  
// results has no errors or warnings, and the workflow completes  
// successfully because the required arguments were passed.  
try  
{  
    Dictionary<string, object> wfparams = new Dictionary<string, object>  
    {  
        { "Operand1", 10 },  
        { "Operand2", 15 }  
    };  
  
    int result = WorkflowInvoker.Invoke(wf, wfparams);  
    Console.WriteLine("Result: {0}", result);  
}  
catch (Exception ex)  
{  
    Console.WriteLine(ex);  
}  

Notes

Dans cet exemple, l'activité racine a été déclarée comme activité Add plutôt qu'Activity comme dans l'exemple précédent. La méthode WorkflowInvoker.Invoke peut ainsi retourner un entier unique qui représente les résultats de l’activité Add, au lieu d’un dictionnaire d’arguments out. La variable wf aurait également pu être déclarée comme Activity<int>.

Lors de la validation d’arguments racines, il incombe à l’application hôte de vérifier que tous les arguments requis sont passés pendant l’appel du flux de travail.

Appel de validation basée sur le code impératif

La validation basée sur le code impératif offre un moyen simple de valider une activité ainsi que les activités dérivées de CodeActivity, AsyncCodeActivity et NativeActivity. Le code de validation est ajouté à l’activité qui détermine les erreurs ou avertissements de validation ajoutés à l’activité. Lorsque la validation est appelée sur l’activité, ces avertissements ou erreurs sont contenus dans la collection retournée par l’appel à Validate. Dans l'exemple suivant, une activité CreateProduct est définie. Si la valeur Cost est supérieure à la valeur Price, une erreur de validation est ajoutée aux métadonnées dans la substitution CacheMetadata.

public sealed class CreateProduct : CodeActivity  
{  
    public double Price { get; set; }  
    public double Cost { get; set; }  
  
    // [RequiredArgument] attribute will generate a validation error
    // if the Description argument is not set.  
    [RequiredArgument]  
    public InArgument<string> Description { get; set; }  
  
    protected override void CacheMetadata(CodeActivityMetadata metadata)  
    {  
        base.CacheMetadata(metadata);  
        // Determine when the activity has been configured in an invalid way.  
        if (this.Cost > this.Price)  
        {  
            // Add a validation error with a custom message.  
            metadata.AddValidationError("The Cost must be less than or equal to the Price.");  
        }  
    }  
  
    protected override void Execute(CodeActivityContext context)  
    {  
        // Not needed for the sample.  
    }  
}  

Dans cet exemple, un workflow est configuré à l'aide de l'activité CreateProduct. Dans ce workflow, la valeur Cost est supérieure à la valeur Price, et l’argument Description requis n’est pas défini. Lorsque la validation est appelée, les erreurs suivantes sont retournées.

Activity wf = new Sequence  
{  
    Activities =
    {  
        new CreateProduct  
        {  
            Cost = 75.00,  
            Price = 55.00  
            // Cost > Price and required Description argument not set.  
        },  
        new WriteLine  
        {  
            Text = "Product added."  
        }  
    }  
};  
  
ValidationResults results = ActivityValidationServices.Validate(wf);  
  
if (results.Errors.Count == 0 && results.Warnings.Count == 0)  
{  
    Console.WriteLine("No warnings or errors");  
}  
else  
{  
    foreach (ValidationError error in results.Errors)  
    {  
        Console.WriteLine("Error: {0}", error.Message);  
    }  
    foreach (ValidationError warning in results.Warnings)  
    {  
        Console.WriteLine("Warning: {0}", warning.Message);  
    }  
}  

Erreur : le coût doit être inférieur ou égal au prix.
Erreur : la valeur pour un argument d'activité 'Description' requis n'a pas été fournie.

Notes

Les auteurs d’activités personnalisées peuvent fournir la logique de validation dans la substitution de la méthode CacheMetadata d’une activité. Toutes les exceptions levées à partir de CacheMetadata ne sont pas traitées comme des erreurs de validation. Ces exceptions ne seront pas détectées par l'appel à Validate et doivent être gérées par l'appelant.

Utilisation de ValidationSettings

Par défaut, toutes les activités dans l'arborescence d'activité sont évaluées lorsque la validation est appelée par ActivityValidationServices. ValidationSettings vous permet de personnaliser la validation de plusieurs façons différentes en configurant ses trois propriétés. SingleLevel spécifie si le validateur doit parcourir l'arborescence d'activité entière ou uniquement appliquer la logique de validation à l'activité fournie. La valeur par défaut pour ce paramètre est false. AdditionalConstraints spécifie un mappage de contraintes supplémentaires, d'un type vers une liste de contraintes. Pour le type de base de chaque activité de l'arborescence en cours de validation, il existe une recherche dans la propriété AdditionalConstraints. Si une liste de contraintes correspondante est trouvée, toutes les contraintes de la liste sont évaluées pour l'activité. OnlyUseAdditionalConstraints spécifie si le validateur doit évaluer toutes les contraintes ou seulement celles spécifiées dans la propriété AdditionalConstraints. La valeur par défaut est false. Grâce aux propriétés AdditionalConstraints et OnlyUseAdditionalConstraints, les auteurs hôtes de flux de travail peuvent ajouter une validation supplémentaire pour les flux de travail comme les contraintes de stratégie pour les outils tels que FxCop. Pour plus d’informations sur les contraintes, consultez Contraintes déclaratives.

Pour utiliser l'objet ValidationSettings, configurez les propriétés de votre choix, puis passez-le dans l'appel à la méthode Validate. Dans cet exemple, un flux de travail, qui consiste en un objet Sequence avec une activité Add personnalisée, est validé. L’activité Add compte deux arguments requis.

public sealed class Add : CodeActivity<int>  
{  
    [RequiredArgument]  
    public InArgument<int> Operand1 { get; set; }  
  
    [RequiredArgument]  
    public InArgument<int> Operand2 { get; set; }  
  
    protected override int Execute(CodeActivityContext context)  
    {  
        return Operand1.Get(context) + Operand2.Get(context);  
    }  
}  

L’activité Add suivante est utilisée dans un objet Sequence, mais ses deux arguments requis ne sont pas liés.

Variable<int> Operand1 = new Variable<int> { Default = 10 };  
Variable<int> Operand2 = new Variable<int> { Default = 15 };  
Variable<int> Result = new Variable<int>();  
  
Activity wf = new Sequence  
{  
    Variables = { Operand1, Operand2, Result },  
    Activities =
    {  
        new Add(),  
        new WriteLine  
        {  
            Text = new InArgument<string>(env => "The result is " + Result.Get(env))  
        }  
    }  
};  

Pour l’exemple suivant, la validation est effectuée avec la propriété SingleLevel définie sur true. Aussi seule l’activité Sequence racine est-elle validée.

ValidationSettings settings = new ValidationSettings  
{  
    SingleLevel = true  
};  
  
ValidationResults results = ActivityValidationServices.Validate(wf, settings);  
  
if (results.Errors.Count == 0 && results.Warnings.Count == 0)  
{  
    Console.WriteLine("No warnings or errors");  
}  
else  
{  
    foreach (ValidationError error in results.Errors)  
    {  
        Console.WriteLine("Error: {0}", error.Message);  
    }  
    foreach (ValidationError warning in results.Warnings)  
    {  
        Console.WriteLine("Warning: {0}", warning.Message);  
    }  
}  

Ce code affiche la sortie suivante :

Aucun avertissement ni aucune erreur Bien que l’activité Add comporte des arguments requis non liés, la validation est réussie, car seule l’activité racine est évaluée. Ce type de validation est utile pour valider uniquement des éléments particuliers d’une arborescence d’activité, par exemple pour valider, dans un concepteur, une modification de propriété d’une activité unique. Notez que si ce workflow est appelé, la validation complète configurée dans le workflow est évaluée et InvalidWorkflowException est levée. ActivityValidationServices et ValidationSettings configurent uniquement la validation explicitement appelée par l'hôte, et non la validation qui a lieu lors de l'appel d'un flux de travail.