Compartir vía


Validación de actividad mediante invocación

La validación de actividad proporciona un método para identificar y notificar errores en la configuración de cualquier actividad antes de su ejecución. La validación se produce cuando se modifica un flujo de trabajo en el diseñador de flujos de trabajo y se muestran los errores o advertencias de validación en el diseñador de flujos de trabajo. La validación también se produce en tiempo de ejecución cuando se invoca un flujo de trabajo y, si se produce algún error de validación, una excepción InvalidWorkflowException es generada por la lógica de validación predeterminada. Windows Workflow Foundation (WF) proporciona la ActivityValidationServices clase que pueden usar la aplicación de flujo de trabajo y los desarrolladores de herramientas para validar explícitamente una actividad. En este tema se describe cómo usar ActivityValidationServices para realizar la validación de actividad.

Uso de los servicios de validación de actividades

ActivityValidationServices tiene dos Validate sobrecargas que se usan para invocar la lógica de validación de una actividad. La primera sobrecarga toma la actividad raíz que se va a validar y devuelve una colección de errores y advertencias de validación. En el ejemplo siguiente, se usa una actividad personalizada Add que tiene dos argumentos necesarios.

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

La Add actividad se usa dentro de un Sequence, pero sus dos argumentos obligatorios no están enlazados, como se muestra en el ejemplo siguiente.

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 flujo de trabajo se puede validar llamando a Validate. Validate devuelve una colección de errores de validación o advertencias contenidos en la actividad y en los elementos secundarios, como se muestra en el ejemplo siguiente.

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

Cuando se llama a Validate en este flujo de trabajo de ejemplo, se devuelven dos errores de validación.

Error: el valor para el argumento necesario de actividad 'Operando2' no fue proporcionado.Error: el valor para el argumento necesario de actividad 'Operando1' no fue proporcionado. Si se invocó este flujo de trabajo, se lanzaría una InvalidWorkflowException excepción, como se muestra en el ejemplo siguiente.

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

System.Activities.InvalidWorkflowException:Se encontraron los siguientes errores al procesar el árbol de flujo de trabajo:'Add': no se proporcionó el valor para un argumento de actividad requerido 'Operand2'.'Add': no se proporcionó el valor para un argumento de actividad requerido 'Operand1'. Para que este flujo de trabajo de ejemplo sea válido, los dos argumentos necesarios de la actividad Add deben estar enlazados. En el ejemplo siguiente, los dos argumentos necesarios están enlazados a variables de flujo de trabajo junto con el valor de resultado. En este ejemplo, el Result argumento está enlazado junto con los dos argumentos necesarios. No es necesario vincular el Result argumento y no causará un error de validación si no se hace. Es responsabilidad del autor del flujo de trabajo enlazar Result si su valor se usa en otra parte del flujo de trabajo.

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

Validación de argumentos necesarios en la actividad raíz

Si la actividad raíz de un flujo de trabajo tiene argumentos, no se enlazan hasta que se invoca el flujo de trabajo y los parámetros se pasan al flujo de trabajo. El flujo de trabajo siguiente pasa la validación, pero se produce una excepción si se invoca el flujo de trabajo sin pasar los argumentos necesarios, como se muestra en el ejemplo siguiente.

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: la configuración del argumento de la actividad raíz es incorrecta.Corrija la definición del flujo de trabajo o proporcione valores de entrada para corregir estos errores:"Agregar": no se proporcionó el valor de un argumento de actividad necesario "Operando2".'Add': no se proporcionó el valor de un argumento de actividad necesario 'Operando1'. Una vez que se pasan los argumentos correctos, el flujo de trabajo se completa correctamente, como se muestra en el ejemplo siguiente.

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:

En este ejemplo, la actividad raíz se declaró como Add en lugar de Activity como en el ejemplo anterior. Esto permite que el WorkflowInvoker.Invoke método devuelva un único entero que represente los resultados de la Add actividad en lugar de un diccionario de out argumentos. La variable wf también podría haberse declarado como Activity<int>.

Al validar los argumentos raíz, es responsabilidad de la aplicación host asegurarse de que se pasan todos los argumentos necesarios cuando se invoca el flujo de trabajo.

Invocar validación imperativa basada en código

La validación imperativa basada en código proporciona una manera sencilla de proporcionar validación sobre sí misma y está disponible para las actividades que derivan de CodeActivity, AsyncCodeActivityy NativeActivity. El código de validación que determina los errores o advertencias de validación se agregan a la actividad. Cuando se invoca la validación en la actividad, estas advertencias o errores se incluyen en la colección devuelta por la llamada a Validate. En el ejemplo siguiente, se define una CreateProduct actividad. Si el Cost es mayor que el Price, se agrega un error de validación a los metadatos en la anulación del 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.
    }
}

En este ejemplo, se configura un flujo de trabajo mediante la CreateProduct actividad . En este flujo de trabajo, Cost es mayor que Price, y no se establece el argumento necesario Description . Cuando se invoca la validación, se devuelven los errores siguientes.

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

Error: El costo debe ser menor o igual que el precio.Error: no se proporcionó el valor de un argumento de actividad requerido 'Description'.

Nota:

Los autores de actividades personalizadas pueden proporcionar lógica de validación en la anulación de CacheMetadata de una actividad. Las excepciones que se inician desde CacheMetadata no se tratan como errores de validación. Estas excepciones escaparán de la llamada a Validate y deben controlarse por el autor de la llamada.

Uso de ValidationSettings

De forma predeterminada, todas las actividades del árbol de actividad se evalúan cuando se invoca la validación mediante ActivityValidationServices. ValidationSettings permite personalizar la validación de varias maneras diferentes mediante la configuración de sus tres propiedades. SingleLevel especifica si el validador debe recorrer todo el árbol de actividad o aplicar solo la lógica de validación a la actividad proporcionada. El valor predeterminado para este valor es false. AdditionalConstraints especifica la asignación de restricciones adicionales de un tipo a una lista de restricciones. Para el tipo base de cada actividad del árbol de actividad que se está validando, hay una búsqueda en AdditionalConstraints. Si se encuentra una lista de restricciones coincidente, se evalúan todas las restricciones de la lista para la actividad. OnlyUseAdditionalConstraints especifica si el validador debe evaluar todas las restricciones o solo las especificadas en AdditionalConstraints. El valor predeterminado es false. AdditionalConstraints y OnlyUseAdditionalConstraints son útiles para que los autores de hosts de flujo de trabajo agreguen validación adicional para flujos de trabajo, como restricciones de directiva para herramientas como FxCop. Para obtener más información sobre las restricciones, vea Restricciones declarativas.

Para usar ValidationSettings, configure las propiedades deseadas y, a continuación, pásela en la llamada a Validate. En este ejemplo, se valida un flujo de trabajo que consta de Sequence con una actividad personalizada Add . La Add actividad tiene dos argumentos necesarios.

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

La actividad siguiente Add se usa en Sequence, pero sus dos argumentos obligatorios no están 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))
        }
    }
};

En el ejemplo siguiente, la validación se realiza con SingleLevel establecido en true, por lo que solo se valida la actividad raíz 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);
    }
}

Este código muestra la salida siguiente:

No hay advertencias ni errores Aunque la Add actividad tiene argumentos necesarios que no están enlazados, la validación se realiza correctamente porque solo se evalúa la actividad raíz. Este tipo de validación es útil para validar solo elementos específicos en un árbol de actividad, como la validación de un cambio de propiedad de una sola actividad en un diseñador. Tenga en cuenta que si se invoca este flujo de trabajo, se evalúa la validación completa configurada en el flujo de trabajo, lo que provocará una InvalidWorkflowException excepción. ActivityValidationServices y ValidationSettings configuran solo la validación invocada explícitamente por el host y no la validación que se produce cuando se invoca un flujo de trabajo.