Invocar validación de actividad
La validación de la actividad proporciona un método para identificar y notificar los errores en la configuración de cualquier actividad antes de su ejecución. La validación se produce cuando un flujo de trabajo se modifica en el diseñador de flujo de trabajo y cuando los errores de validación o advertencias se muestran en el diseñador de flujo de trabajo. La validación también se produce en tiempo de ejecución cuando se invoca un flujo de trabajo y si se producen algunos errores de validación; la lógica de validación predeterminada produce InvalidWorkflowException. Windows Workflow Foundation (WF) proporciona la clase ActivityValidationServices que la aplicación de flujo de trabajo y los desarrolladores de herramientas pueden usar para validar explícitamente una actividad. En este tema se describe cómo usar ActivityValidationServices para realizar la validación de actividad.
Usar ActivityValidationServices
ActivityValidationServices tiene dos sobrecargas de Validate 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 de validación y advertencias. En el siguiente ejemplo, se usa una actividad Add
personalizada 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 actividad Add
se usa dentro de Sequence, aunque no se enlazan sus dos argumentos necesarios, tal y como se muestra en el siguiente ejemplo.
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 o advertencias de validación contenidos por la actividad y cualquier elemento secundario, tal y como se muestra en el siguiente ejemplo.
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: Value for a required activity argument 'Operand2' was not supplied.
Error: Value for a required activity argument 'Operand1' was not supplied. Si se invocara este flujo de trabajo, se produciría una excepción InvalidWorkflowException, tal y como se muestra en el siguiente ejemplo.
try
{
WorkflowInvoker.Invoke(wf);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
System.Activities.InvalidWorkflowException:
Se encontraron los errores siguientes al procesar el árbol de flujo de trabajo:"Add": No se suministró el valor de un argumento de actividad obligatorio "Operand2"."Add": No se suministró el valor de un argumento de actividad obligatorio "Operand1". Para que el flujo de este ejemplo sea válido, se deben enlazar los dos argumentos obligatorios de la actividad Add
. En el siguiente ejemplo, los dos argumentos necesarios se enlazan con las variables de flujo de trabajo junto con el valor de resultado. En este ejemplo, el argumento Result se enlaza con los dos argumentos necesarios. No se exige que se enlace el argumento Result y no provoca un error de validación si no lo está. Es responsabilidad del autor del flujo de trabajo enlazar Result si su valor se usa en otra parte en el 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, estos no se enlazan hasta que se invoca el flujo de trabajo y los parámetros se pasan al flujo de trabajo. El siguiente flujo de trabajo pasa la validación, pero se produce una excepción si el flujo de trabajo se invoca sin pasar los argumentos necesarios, tal y 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: Los valores de argumento de la actividad raíz son incorrectos.
Corrija la definición del flujo de trabajo o suministre valores de entrada para corregir estos errores:"Add': No se suministró el valor de un argumento de actividad obligatorio "Operand2"."Add": No se suministró el valor de un argumento de actividad obligatorio "Operand1". Una vez que se pasan los argumentos correctos, el flujo de trabajo se completa correctamente, tal 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
, tal y como se especificó en el ejemplo anterior. Esto permite al método WorkflowInvoker.Invoke
devolver un entero único que representa los resultados de la actividad Add
en lugar de un diccionario de argumentos out
. La variable wf
también se puede declarar como Activity<int>
.
Al validar los argumentos raíz, la responsabilidad de la aplicación host es asegurarse de que se pasan todos los argumentos necesarios cuando se invoca el flujo de trabajo.
Invocar la validación imperativa basada en código
La validación basada en código imperativo proporciona una manera sencilla para que una actividad proporcione la validación sobre ella misma y está disponible para aquellas actividades que derivan de CodeActivity, AsyncCodeActivity y NativeActivity. El código de validación se agrega a la actividad que determina cualquier error de validación o advertencias. Cuando la validación se invoca en la actividad, estas advertencias o errores están contenidos en la colección devuelta por la llamada a Validate. En el ejemplo siguiente, se define una actividad CreateProduct
. Si Cost
es mayor que Price
, se agrega un error de validación a los metadatos en la invalidación de 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, un flujo de trabajo se configura mediante la actividad CreateProduct
. En este flujo de trabajo, Cost
es mayor que Price
, y el argumento Description
necesario no está establecido. Cuando se invoca la validación, se devuelven los siguientes errores.
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: Value for a required activity argument 'Description' was not supplied.
Nota
Los autores de actividades personalizadas pueden proporcionar lógica de validación en la invalidación del método CacheMetadata de una actividad. Cualquier excepción que se produzca desde el método CacheMetadata no se trata como errores de validación. Estas excepciones escaparán de la llamada al método Validate y serán administradas por el autor de la llamada.
Usar ValidationSettings
De forma predeterminada, todas las actividades del árbol de actividad se evalúan cuando la validación se invoca mediante ActivityValidationServices. ValidationSettings permite personalizar la validación de varias maneras diferentes configurando sus tres propiedades. SingleLevel especifica si el validador debe recorrer el árbol de actividad completo o solo aplicar lógica de validación a la actividad proporcionada. Éste es el valor predeterminado de false
. AdditionalConstraints especifica una asignación de restricción adicional de un tipo a una lista de restricciones. Para el tipo base de cada actividad en el árbol de actividad que se esté validando, hay una búsqueda en AdditionalConstraints. Si se encuentra una lista de restricciones que coincida, todas las restricciones de la lista se evalúan 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 host de flujo de trabajo agreguen validación adicional a los flujos de trabajo, por ejemplo restricciones de directivas para herramientas como FxCop. Para más información sobre las restricciones, consulte Restricciones declarativas.
Para usar ValidationSettings, configure las propiedades que desee y, a continuación, páselo en la llamada a Validate. En este ejemplo, se valida un flujo de trabajo que está compuesto de un Sequence con una actividad Add
personalizada. La actividad Add
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 siguiente actividad Add
se usa en Sequence, pero no se enlazan sus dos argumentos necesarios.
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 la propiedad SingleLevel definida en true
, por lo que sólo 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 el siguiente resultado:
Ninguna advertencia o error Aunque la actividad Add
haya exigido argumentos que no están enlazados, la validación será correcta porque solo se evaluó la actividad raíz. Este tipo de validación es útil sólo para validar los elementos concretos en un árbol de actividad, como la validación de un cambio de propiedad de una actividad única 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 y se produciría InvalidWorkflowException. ActivityValidationServices y ValidationSettings solo configuran la validación explícitamente invocada por el host, y no la validación que se produce cuando se invoca un flujo de trabajo.