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


Вызов проверки действия

Проверка действия предоставляет метод для выявления ошибок и отчетов об ошибках в конфигурации любого действия до его выполнения. Когда рабочий процесс модифицируется в конструкторе, выполняется проверка и любые ошибки или предупреждения, выявленные в ее ходе, отображаются в конструкторе. Также проверка происходит во время выполнения, когда вызывается рабочий процесс, и при появлении каких-либо ошибок проверки логикой проверки по умолчанию выдается исключение InvalidWorkflowException. Windows Workflow Foundation (WF) предоставляет ActivityValidationServices класс, который может использоваться приложением рабочего процесса и разработчиками инструментов для явной проверки действия. В этом разделе описывается, как использовать ActivityValidationServices для выполнения проверки действия.

Использование служб ActivityValidationServices

ActivityValidationServices имеет две Validate перегрузки, которые используются для вызова логики проверки действия. Первая перегруженная форма получает проверяемое корневое действие и возвращает коллекцию ошибок и предупреждений. В следующем примере использовано пользовательское действие Add с двумя обязательными аргументами.

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

Следующее действие Add используется внутри Sequence, но два его обязательных аргумента не связаны, как показано в следующем примере.

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

Этот рабочий процесс может быть проверен путем вызова Validate. Validate возвращает коллекцию всех ошибок и предупреждений проверки, содержащихся в действии (и в любых его дочерних действиях), как показано в следующем примере.

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

Когда Validate вызывается для данного образца рабочего процесса, возвращаются две выявленные при проверке ошибки.

Ошибка. Значение для требуемого аргумента действия "Операнд2" не было предоставлено.
Ошибка. Значение для требуемого аргумента действия "Операнд1" не было предоставлено. Если этот рабочий процесс был вызван, будет сформировано исключение InvalidWorkflowException, как показано в следующем примере.

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

System.Activities.InvalidWorkflowException:
При обработке дерева рабочего процесса произошли следующие ошибки: "Добавить": значение для требуемого аргумента действия "Operand2" не было предоставлено. Add': значение для требуемого аргумента действия "Operand1" не было предоставлено. Чтобы этот пример рабочего процесса был допустимым, необходимо привязать два обязательных аргумента Add действия. В следующем примере два обязательных аргумента связаны с переменными рабочего процесса и со значением результата. В данном примере аргумент Result связан вместе с двумя обязательными аргументами. Аргумент Result связывать необязательно. Если он не связан, то при проверке это не вызовет ошибку. В обязанности автора рабочего процесса входит связать Result, если его значение используется в другом месте рабочего процесса.

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

Проверка требуемых аргументов для корневого действия

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

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: неправильные параметры аргумента корневого действия.
Исправьте определение рабочего процесса или укажите входные значения для устранения этих ошибок:'Add': значение для требуемого аргумента действия "Операнд2" не было предоставлено. Add': значение для требуемого аргумента действия "Operand1" не было предоставлено. После прохождения правильных аргументов рабочий процесс успешно завершается, как показано в следующем примере.

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

Примечание.

В данном примере корневое действие было объявлено как Add (вместо Activity), как в предыдущем примере Это позволяет методу WorkflowInvoker.Invoke возвратить отдельное целочисленное значение, представляющее результаты действия Add вместо словаря аргументов out. Переменную wf также можно было объявить как Activity<int>.

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

Вызов императивной проверки на уровне кода

Проверка в императивном коде доступна для действий, производных от CodeActivity, AsyncCodeActivity и NativeActivity, и служит простым способом автономной проверки действия. Код проверки, определяющий все ошибки и предупреждения проверки, добавляется к действию. При вызове проверки допустимости для действий эти предупреждения или ошибки содержатся в коллекции, возвращаемой вызовом метода Validate. В следующем примере определяется действие CreateProduct . Если значение Cost больше Price, к метаданным в переопределении 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.  
    }  
}  

В этом примере рабочий процесс создается с помощью действия CreateProduct. В этом рабочем процессе Cost больше, чем Price, а обязательный аргумент Description не задан. При вызове проверки допустимости возвращаются следующие ошибки.

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

Ошибка. Стоимость должна быть меньше или равна цене.
Ошибка. Значение для обязательного аргумента действия "Описание" не было предоставлено.

Примечание.

Авторы настраиваемых действий могут размещать логику проверки в переопределенном методе CacheMetadata действия. Исключения, вызванные в методе CacheMetadata, не считаются ошибками проверки. Эти исключения перейдут из метода Validate к вызывающему объекту, который должен их обработать.

Использование ValidationSettings

По умолчанию все действия из дерева действий вычисляются при вызове проверки службой ActivityValidationServices. ValidationSettings позволяет настраивать проверку несколькими способами посредством трех ее свойств. SingleLevel указывает, должен проверяющий элемент управления пройти по всему дереву действий или применить логику проверки только к предоставленному действию. Значение по умолчанию для этого свойства - false. AdditionalConstraints задает дополнительное сопоставление ограничений от типа к списку ограничений. В AdditionalConstraints имеется уточняющий запрос для базового типа каждого действия из проверяемого дерева действий. Если найден подходящий список ограничений, то все ограничения в нем вычисляются для действия. OnlyUseAdditionalConstraints указывает, должен проверяющий элемент управления вычислять все ограничения или только указанные в AdditionalConstraints. Значение по умолчанию — false. AdditionalConstraints и OnlyUseAdditionalConstraints помогают авторам узлов рабочих процессов добавлять дополнительные проверки рабочих процессов, например ограничения политики для таких инструментов, как FxCop. Дополнительные сведения об ограничениях см. в разделе "Декларативные ограничения".

Чтобы использовать ValidationSettings, настройте требуемые свойства и передайте этот объект в вызове Validate. В данном примере проверяется рабочий процесс, состоящий из Sequence с пользовательским действием Add. У действия Add есть два обязательных аргумента.

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

Следующее действие Add используется в Sequence, но два его обязательных аргумента не связаны.

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

В следующем примере проверка выполняется, когда SingleLevel задано значение true, так что проверяется только корневое действие Sequence.

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

Этот код отображает следующие данные.

Никаких предупреждений или ошибок, несмотря на то, что действие Add имеет обязательные аргументы, проверка выполняется успешно, так как вычисляется только корневое действие. Такой тип проверки полезен, когда нужно проверить только определенные элементы дерева действий, например изменение свойства отдельного действия в конструкторе. Обратите внимание, что если этот рабочий процесс вызван, то выполняется полная проверка, настроенная в рабочем процессе, и создается исключение InvalidWorkflowException. ActivityValidationServices и ValidationSettings настраивают только проверку, явно вызываемую узлом, но невыполняемую при вызове рабочего процесса.