Поделиться через


Декларативные ограничения

Декларативные ограничения - это мощный метод проверки допустимости действия и его связей с другими действиями. Ограничения для действий настраиваются во время процесса создания, однако дополнительные ограничения также могут задаваться ведущим приложением рабочего процесса. В этом разделе приводятся общие сведения об использовании декларативных ограничений для обеспечения проверки допустимости действий.

Использование декларативных ограничений

Ограничение - это действие, содержащее логику проверки допустимости. Это действие ограничения может быть создано в коде или в XAML. После создания действия ограничения автор действия добавляет данное ограничение в свойство Constraints действия, которое должно быть проверено, или использует ограничение для реализации дополнительной проверки с помощью свойства AdditionalConstraints экземпляра ValidationSettings. Логика проверки допустимости может состоять из простых проверок допустимости, например проверки метаданных действия, но она также может выполнять проверку допустимости, учитывающую связь текущего действия с его родительскими, дочерними и одноуровневыми действиями. Ограничения создаются посредством использования действия Constraint<T>; кроме того, предоставляются несколько дополнительных действий проверки допустимости, облегчающие создание ошибок и предупреждений проверки допустимости и выдачу сведений о связанных действиях в рабочем процессе.

AssertValidation и AddValidationError

Действие AssertValidation вычисляет выражение, на которое ссылается его свойство Assertion, и, если в результате вычисления получается значение false, к ValidationResults добавляется ошибка или предупреждение проверки допустимости. Свойство Message описывает ошибку проверки допустимости; свойство IsWarning указывает, является ли неудачная проверка допустимости ошибкой или предупреждением. Значение IsWarning по умолчанию — false.

В следующем примере объявляется ограничение, возвращающее предупреждение проверки допустимости, если длина DisplayName действия, для которого выполняется проверка, меньше или равна двум символам. Параметр универсального типа, используемый для Constraint<T>, задает тип действия, проверяемого ограничением. Это ограничение использует действие Activity в качестве универсального типа. Оно может использоваться для проверки допустимости всех типов действий.

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."),  
            }  
        }  
    };  
}  

Чтобы задать данное ограничение для действия, его следует добавить в Constraints для действия, как показано в следующем примере кода.

public sealed class SampleActivity : CodeActivity  
{  
    public SampleActivity()  
    {  
        base.Constraints.Add(ActivityDisplayNameIsNotSetWarning());  
    }  
  
    // Activity implementation omitted.  
}  

Ведущее приложение может также задавать это ограничение для действий в рабочем процессе посредством использования AdditionalConstraints. Этот вариант описывается в следующем разделе.

Действие AddValidationError используется для создания ошибки или предупреждения проверки допустимости без необходимости вычисления выражения. Его свойства подобны свойствам AssertValidation; оно может использоваться совместно с действиями управления потоком ограничения, например с действием If.

Действия связей рабочих процессов

Доступны несколько действий проверки допустимости, которые предоставляют сведения о других действиях в рабочем процессе относительно проверяемого действия. GetParentChain возвращает коллекцию действий, содержащую все действия, лежащие между текущим и корневым действиями. GetChildSubtree предоставляет коллекцию действий, содержащую дочерние действия в рекурсивном шаблоне, и GetWorkflowTree возвращает все действия в рабочем процессе.

В следующем примере определяется действие CreateState . Действие CreateState должно содержаться в действии CreateCountry; метод GetParent возвращает ограничение, принудительно реализующее это требование. GetParent использует действие GetParentChain совместно с действием ForEach<T> для проверки родительских действий действия CreateState, чтобы определить, удовлетворяется ли это требование.

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

Дополнительные ограничения

Авторы ведущих приложений рабочих процессов могут задавать дополнительные ограничения проверки допустимости для действий в рабочем процессе, создавая ограничения и добавляя их к словарю AdditionalConstraints экземпляра ValidationSettings. Каждый элемент в AdditionalConstraints содержит тип действия, к которому применяются ограничения, а также список дополнительных ограничений для этого типа действия. При вызове проверки допустимости для рабочего процесса каждое действие указанного типа, включая производные классы, проверяется на соответствие ограничениям. В этом примере ограничение ActivityDisplayNameIsNotSetWarning из предыдущего раздела применяется ко всем действиям в рабочем процессе.

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);  
    }  
}  

Если свойство OnlyUseAdditionalConstraints у ValidationSettings имеет значение true, то при вызове проверки допустимости путем вызова Validate выполняется проверка только дополнительных ограничений. Это может быть полезно при проверке рабочих процессов по отдельным конфигурациям проверки. Необходимо отметить, что при вызове рабочего процесса выполняется проверка логики проверки, настроенной в рабочем процессе; для запуска рабочего процесса проверка должна быть пройдена успешно. Дополнительные сведения о вызове проверки см. в разделе "Вызов проверки действия".