Contraintes déclaratives
Les contraintes déclaratives fournissent une méthode puissante de validation d’une activité et de ses relations avec d’autres activités. Les contraintes sont configurées pour une activité pendant le processus de création, mais les contraintes supplémentaires peuvent également être spécifiées par l'hôte du workflow. Cette rubrique fournit une vue d’ensemble de l’utilisation de contraintes déclaratives afin de fournir la validation d’activité.
Utilisation des contraintes déclaratives
Une contrainte est une activité qui contient la logique de validation. Cette activité de contrainte peut être créée dans le code ou en XAML. Une fois une activité de contrainte créée, les auteurs d’activités ajoutent cette contrainte à la propriété Constraints de l’activité à valider, ou ils utilisent la contrainte pour fournir la validation supplémentaire à l’aide de la propriété AdditionalConstraints d’une instance ValidationSettings. La logique de validation peut consister en validations simples telles que la validation des métadonnées d'une activité, mais il peut également effectuer une validation qui tient compte de la relation de l'activité actuelle à son parent, enfants et activités de mêmes parents. Les contraintes sont créées à l’aide de l’activité Constraint<T>, et plusieurs activités de validation supplémentaires sont fournies pour aider à la création d’erreurs de validation et avertissements et fournir des informations à propos des activités connexes dans le workflow.
AssertValidation et AddValidationError
L’activité AssertValidation évalue l’expression référencée par sa propriété Assertion, et si l’expression donne la valeur false
, une erreur de validation ou un avertissement est ajoutée à ValidationResults. La propriété Message décrit l’erreur de validation et la propriété IsWarning indique si l’échec de la validation est une erreur ou un avertissement. La valeur par défaut pour IsWarning est false
.
Dans l'exemple suivant, une contrainte est déclarée et renvoie un avertissement de validation si le DisplayName de l'activité qui est validée comprend deux caractères ou moins. Le paramètre de type générique utilisé pour Constraint<T> spécifie le type d’activité validé par la contrainte. Cette contrainte utilise Activity comme type générique et peut être utilisée pour valider tous les types d'activités.
public static Constraint ActivityDisplayNameIsNotSetWarning()
{
DelegateInArgument<Activity> element = new DelegateInArgument<Activity>();
return new Constraint<Activity>
{
Body = new ActivityAction<Activity, ValidationContext>
{
Argument1 = element,
Handler = new AssertValidation
{
IsWarning = true,
Assertion = new InArgument<bool>(env => (element.Get(env).DisplayName.Length > 2)),
Message = new InArgument<string>("It is a best practice to have a DisplayName of more than 2 characters."),
}
}
};
}
Pour spécifier cette contrainte pour une activité, elle est ajoutée au Constraints de l'activité, comme indiqué dans l'exemple de code suivant.
public sealed class SampleActivity : CodeActivity
{
public SampleActivity()
{
base.Constraints.Add(ActivityDisplayNameIsNotSetWarning());
}
// Activity implementation omitted.
}
Cette contrainte pourrait également être spécifiée pour les activités d'un workflow par l'hôte à l'aide de AdditionalConstraints. La section suivante explique la démarche à suivre.
L’activité AddValidationError est utilisée pour générer une erreur de validation ou un avertissement sans recourir à l’évaluation d’une expression. Ses propriétés sont semblables à AssertValidation et elle peut être utilisée avec des activités de contrôle de flux d'une contrainte telles que l'activité If.
Activités de la relation du workflow
Plusieurs activités de validation sont disponibles, qui fournissent des informations sur les autres activités dans le flux de travail par rapport à l’activité en cours de validation. GetParentChain retourne une collection d'activités qui contient toutes les activités entre l'activité actuelle et l'activité racine. GetChildSubtree fournit une collection d'activités qui contient les activités enfants dans un modèle récurrent, et GetWorkflowTree obtient toutes les activités dans le workflow.
Dans l'exemple suivant, une activité CreateState
est définie. L'activité CreateState
doit être contenue dans une activité CreateCountry
, et la méthode GetParent
retourne une contrainte qui applique cette spécification. GetParent
utilise l'activité GetParentChain conjointement avec une activité ForEach<T> pour examiner les activités parentes de l'activité CreateState
et déterminer si la spécification est satisfaite.
public sealed class CreateState : CodeActivity
{
public CreateState()
{
base.Constraints.Add(CheckParent());
this.Cities = new List<Activity>();
}
public List<Activity> Cities { get; set; }
public string Name { get; set; }
static Constraint CheckParent()
{
DelegateInArgument<CreateState> element = new DelegateInArgument<CreateState>();
DelegateInArgument<ValidationContext> context = new DelegateInArgument<ValidationContext>();
Variable<bool> result = new Variable<bool>();
DelegateInArgument<Activity> parent = new DelegateInArgument<Activity>();
return new Constraint<CreateState>
{
Body = new ActivityAction<CreateState,ValidationContext>
{
Argument1 = element,
Argument2 = context,
Handler = new Sequence
{
Variables =
{
result
},
Activities =
{
new ForEach<Activity>
{
Values = new GetParentChain
{
ValidationContext = context
},
Body = new ActivityAction<Activity>
{
Argument = parent,
Handler = new If()
{
Condition = new InArgument<bool>((env) => object.Equals(parent.Get(env).GetType(),typeof(CreateCountry))),
Then = new Assign<bool>
{
Value = true,
To = result
}
}
}
},
new AssertValidation
{
Assertion = new InArgument<bool>(result),
Message = new InArgument<string> ("CreateState has to be inside a CreateCountry activity"),
}
}
}
}
};
}
protected override void Execute(CodeActivityContext context)
{
// not needed for the sample
}
}
Contraintes supplémentaires
Les auteurs hôte du workflow peuvent spécifier des contraintes de validation supplémentaires pour les activités d'un workflow en créant des contraintes et en les ajoutant au dictionnaire AdditionalConstraints d'une instance ValidationSettings. Chaque élément dans AdditionalConstraints contient le type d'activité pour laquelle les contraintes s'appliquent et une liste des contraintes supplémentaires pour ce type d'activité. Lorsque la validation est appelée pour le workflow, chaque activité du type spécifié, notamment les classes dérivées, évalue les contraintes. Dans cet exemple, la contrainte ActivityDisplayNameIsNotSetWarning
de la section précédente est appliquée à toutes les activités dans un workflow.
Activity wf = new Sequence
{
// Workflow Details Omitted.
};
ValidationSettings settings = new ValidationSettings()
{
AdditionalConstraints =
{
{typeof(Activity), new List<Constraint> {ActivityDisplayNameIsNotSetWarning()}},
}
};
// Validate the workflow.
ValidationResults results = ActivityValidationServices.Validate(wf, settings);
// Evaluate the results.
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 in " + error.Source.DisplayName + ": " + error.Message);
}
foreach (ValidationError warning in results.Warnings)
{
Console.WriteLine("Warning in " + warning.Source.DisplayName + ": " + warning.Message);
}
}
Si la propriété OnlyUseAdditionalConstraints de ValidationSettings est définie sur true
, seules les contraintes supplémentaires spécifiées sont évaluées lorsque la validation est appelée en invoquant Validate. Cela peut être utile pour inspecter les workflows et rechercher des configurations de validation spécifiques. Notez toutefois que lorsque le workflow est appelé, la logique de validation configurée dans le workflow est évaluée et doit aboutir pour que le workflow démarre avec succès. Pour plus d’informations sur l’appel de validation, consultez Invocation de la validation d’activité.