Partilhar via


Invocando a validação da atividade

A validação de atividade fornece um método para identificar e relatar erros na configuração de qualquer atividade antes de sua execução. A validação ocorre quando um fluxo de trabalho é modificado no designer de fluxo de trabalho e quaisquer erros ou avisos de validação são exibidos no designer de fluxo de trabalho. A validação também ocorre em tempo de execução quando um fluxo de trabalho é invocado e, se ocorrerem erros de validação, um InvalidWorkflowException é gerado pela lógica de validação padrão. O Windows Workflow Foundation (WF) fornece a ActivityValidationServices classe que pode ser usada por desenvolvedores de aplicativos e ferramentas de fluxo de trabalho para validar explicitamente uma atividade. Este tópico descreve como usar ActivityValidationServices para executar a validação de atividades.

Usando ActivityValidationServices

ActivityValidationServices tem duas Validate sobrecargas que são usadas para invocar a lógica de validação de uma atividade. A primeira sobrecarga leva a atividade raiz a ser validada e retorna uma coleção de erros de validação e avisos. No exemplo a seguir, é usada uma atividade personalizada Add que tem dois argumentos necessários.

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

A Add atividade é usada dentro de um Sequence, mas seus dois argumentos necessários não são vinculados, como mostrado no exemplo a seguir.

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

Este fluxo de trabalho pode ser validado chamando Validate. Validate Retorna uma coleção de quaisquer erros de validação ou avisos contidos pela atividade e quaisquer filhos, conforme mostrado no exemplo a seguir.

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

Quando Validate é chamado neste fluxo de trabalho de exemplo, dois erros de validação são retornados.

Erro: O valor de um argumento de atividade necessária 'Operand2' não foi fornecido.
Erro: O valor de um argumento de atividade necessário 'Operand1' não foi fornecido. Se esse fluxo de trabalho fosse invocado, um InvalidWorkflowException seria lançado, conforme mostrado no exemplo a seguir.

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

System.Activities.InvalidWorkflowException:
Os seguintes erros foram encontrados durante o processamento da árvore de fluxo de trabalho:'Adicionar': O valor para um argumento de atividade necessário 'Operand2' não foi fornecido.' Add': O valor de um argumento de atividade necessário 'Operand1' não foi fornecido. Para que este fluxo de trabalho de exemplo seja válido, os dois argumentos necessários da Add atividade devem ser vinculados. No exemplo a seguir, os dois argumentos necessários são vinculados a variáveis de fluxo de trabalho juntamente com o valor do resultado. Neste exemplo, o Result argumento é vinculado junto com os dois argumentos necessários. O Result argumento não precisa ser vinculado e não causa um erro de validação se não for. É responsabilidade do autor do fluxo de trabalho vincular Result se seu valor for usado em outro lugar no fluxo de trabalho.

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

Validando argumentos necessários na atividade raiz

Se a atividade raiz de um fluxo de trabalho tiver argumentos, eles não serão vinculados até que o fluxo de trabalho seja invocado e os parâmetros sejam passados para o fluxo de trabalho. O fluxo de trabalho a seguir passa na validação, mas uma exceção é lançada se o fluxo de trabalho for invocado sem passar os argumentos necessários, conforme mostrado no exemplo a seguir.

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: As configurações de argumento da atividade raiz estão incorretas.
Corrija a definição do fluxo de trabalho ou forneça valores de entrada para corrigir esses erros:'Adicionar': O valor para um argumento de atividade necessário 'Operand2' não foi fornecido.' Add': O valor de um argumento de atividade necessário 'Operand1' não foi fornecido. Depois que os argumentos corretos são passados, o fluxo de trabalho é concluído com êxito, conforme mostrado no exemplo a seguir.

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

Nota

Neste exemplo, a atividade raiz foi declarada como Add em vez de Activity como no exemplo anterior. Isso permite que o WorkflowInvoker.Invoke método retorne um único inteiro que representa os resultados da Add atividade em vez de um dicionário de out argumentos. A variável wf também poderia ter sido declarada como Activity<int>.

Ao validar argumentos raiz, é responsabilidade do aplicativo host garantir que todos os argumentos necessários sejam passados quando o fluxo de trabalho for invocado.

Invocando validação imperativa baseada em código

A validação baseada em código imperativo fornece uma maneira simples para uma atividade fornecer validação sobre si mesma, e está disponível para atividades que derivam de CodeActivity, AsyncCodeActivitye NativeActivity. O código de validação que determina quaisquer erros ou avisos de validação é adicionado à atividade. Quando a validação é invocada na atividade, esses avisos ou erros estão contidos na coleção retornada pela chamada para Validate. No exemplo a seguir, uma CreateProduct atividade é definida. Se o Cost for maior que o Price, um erro de validação será adicionado aos metadados na CacheMetadata substituição.

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

Neste exemplo, um fluxo de trabalho é configurado usando a CreateProduct atividade. Neste fluxo de trabalho, o Cost é maior que o Price, e o argumento necessário Description não está definido. Quando a validação é invocada, os seguintes erros são retornados.

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

Erro: O Custo deve ser menor ou igual ao Preço.
Erro: O valor de um argumento de atividade necessário 'Descrição' não foi fornecido.

Nota

Os autores de atividades personalizadas podem fornecer lógica de validação na substituição de CacheMetadata uma atividade. Quaisquer exceções lançadas não são tratadas como erros de CacheMetadata validação. Essas exceções escaparão da chamada e Validate devem ser tratadas pelo chamador.

Usando ValidationSettings

Por padrão, todas as atividades na árvore de atividades são avaliadas quando a validação é invocada pelo ActivityValidationServices. ValidationSettings permite que a validação seja personalizada de várias maneiras diferentes, configurando suas três propriedades. SingleLevel Especifica se o validador deve percorrer toda a árvore de atividades ou aplicar apenas a lógica de validação à atividade fornecida. O padrão para esse valor é false. AdditionalConstraints Especifica o mapeamento de restrições adicionais de um tipo para uma lista de restrições. Para o tipo de base de cada atividade na árvore de atividades que está sendo validada, há uma pesquisa em AdditionalConstraints. Se uma lista de restrições correspondente for encontrada, todas as restrições na lista serão avaliadas para a atividade. OnlyUseAdditionalConstraints Especifica se o validador deve avaliar todas as restrições ou apenas as especificadas em AdditionalConstraints. O valor predefinido é false. AdditionalConstraints e OnlyUseAdditionalConstraints são úteis para que os autores do host do fluxo de trabalho adicionem validação adicional para fluxos de trabalho, como restrições de política para ferramentas como o FxCop. Para obter mais informações sobre restrições, consulte Restrições declarativas.

Para usar ValidationSettingso , configure as propriedades desejadas e passe-as na chamada para Validate. Neste exemplo, um fluxo de trabalho que consiste em uma Sequence com uma atividade personalizada Add é validado. A Add atividade tem dois argumentos necessários.

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

A atividade a seguir Add é usada em um Sequence, mas seus dois argumentos necessários não estão vinculados.

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

Para o exemplo a seguir, a validação é executada com SingleLevel set como true, portanto, somente a atividade raiz Sequence é validada.

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

Este código exibe a seguinte saída:

Sem avisos ou erros Embora a atividade tenha argumentos necessários que não estão vinculados, a Add validação é bem-sucedida porque apenas a atividade raiz é avaliada. Esse tipo de validação é útil para validar apenas elementos específicos em uma árvore de atividades, como a validação de uma alteração de propriedade de uma única atividade em um designer. Observe que, se esse fluxo de trabalho for invocado, a validação completa configurada no fluxo de trabalho será avaliada e um InvalidWorkflowException será lançado. ActivityValidationServices e ValidationSettings configure apenas a validação explicitamente invocada pelo host, e não a validação que ocorre quando um fluxo de trabalho é invocado.