Nota
L'accés a aquesta pàgina requereix autorització. Podeu provar d'iniciar la sessió o de canviar els directoris.
L'accés a aquesta pàgina requereix autorització. Podeu provar de canviar els directoris.
AsyncCodeActivity proporciona a los autores de actividades una clase base que permite que las actividades derivadas implementen lógica de ejecución asincrónica. Esto resulta útil para las actividades personalizadas que deben realizar trabajos asincrónicos sin contener el subproceso del programador de flujo de trabajo y bloquear las actividades que puedan ejecutarse en paralelo. En este tema se proporciona información general sobre cómo crear actividades asincrónicas personalizadas mediante AsyncCodeActivity.
Uso de AsyncCodeActivity
System.Activities ofrece a los autores de actividades personalizadas diferentes clases base para distintas necesidades de creación de actividades. Cada uno incluye una semántica determinada y proporciona al autor de flujo de trabajo (y al tiempo de ejecución de actividad) un contrato correspondiente. Una actividad basada en AsyncCodeActivity es una actividad que realiza el trabajo de forma asincrónica con respecto al subproceso del planificador y cuya lógica de ejecución se expresa en código administrado. Como resultado de ir asincrónico, un AsyncCodeActivity puede inducir un punto inactivo durante la ejecución. Debido a la naturaleza volátil del trabajo asincrónico, un AsyncCodeActivity siempre crea un bloque no persistente durante la ejecución de la actividad. Esto evita que el tiempo de ejecución del flujo de trabajo conserve la instancia de flujo de trabajo en medio del trabajo asincrónico y también impide que la instancia de flujo de trabajo se descargue mientras se ejecuta el código asincrónico.
Métodos de AsyncCodeActivity
Las actividades que derivan de AsyncCodeActivity pueden crear lógica de ejecución asincrónica reemplazando los BeginExecute métodos y EndExecute con código personalizado. Cuando el tiempo de ejecución los llama, a estos métodos se les pasa un AsyncCodeActivityContext.
AsyncCodeActivityContext permite al autor de la actividad proporcionar el estado compartido en la propiedad UserState del contexto de BeginExecute/ EndExecute. En el ejemplo siguiente, una GenerateRandom actividad genera un número aleatorio de forma asincrónica.
public sealed class GenerateRandom : AsyncCodeActivity<int>
{
static Random r = new Random();
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
// Create a delegate that references the method that implements
// the asynchronous work. Assign the delegate to the UserState,
// invoke the delegate, and return the resulting IAsyncResult.
Func<int> GetRandomDelegate = new Func<int>(GetRandom);
context.UserState = GetRandomDelegate;
return GetRandomDelegate.BeginInvoke(callback, state);
}
protected override int EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
// Get the delegate from the UserState and call EndInvoke
Func<int> GetRandomDelegate = (Func<int>)context.UserState;
return (int)GetRandomDelegate.EndInvoke(result);
}
int GetRandom()
{
// This activity simulates taking a few moments
// to generate the random number. This code runs
// asynchronously with respect to the workflow thread.
Thread.Sleep(5000);
return r.Next(1, 101);
}
}
La actividad de ejemplo anterior deriva de AsyncCodeActivity<TResult> y tiene un OutArgument<int> elevado llamado Result. El valor devuelto por el método GetRandom se extrae y devuelve mediante la sobreescritura EndExecute, y este valor se establece como el valor Result. Las actividades asincrónicas que no devuelven un resultado deben derivarse de AsyncCodeActivity. En el ejemplo siguiente, se define una DisplayRandom actividad que deriva de AsyncCodeActivity. Esta actividad es similar a la GetRandom actividad, pero en lugar de devolver un resultado, muestra un mensaje a la consola.
public sealed class DisplayRandom : AsyncCodeActivity
{
static Random r = new Random();
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
// Create a delegate that references the method that implements
// the asynchronous work. Assign the delegate to the UserState,
// invoke the delegate, and return the resulting IAsyncResult.
Action GetRandomDelegate = new Action(GetRandom);
context.UserState = GetRandomDelegate;
return GetRandomDelegate.BeginInvoke(callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
// Get the delegate from the UserState and call EndInvoke
Action GetRandomDelegate = (Action)context.UserState;
GetRandomDelegate.EndInvoke(result);
}
void GetRandom()
{
// This activity simulates taking a few moments
// to generate the random number. This code runs
// asynchronously with respect to the workflow thread.
Thread.Sleep(5000);
Console.WriteLine($"Random Number: {r.Next(1, 101)}");
}
}
Tenga en cuenta que, dado que no hay ningún valor devuelto, DisplayRandom usa un Action en lugar de un Func<T,TResult> para invocar su delegado y el delegado no devuelve ningún valor.
AsyncCodeActivity también proporciona una Cancel anulación. Aunque BeginExecute y EndExecute son sobrescrituras necesarias, Cancel es opcional y se puede sobrescribir para que la actividad pueda limpiar el estado asincrónico pendiente cuando se cancela o aborta. Si la limpieza es posible y AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested es true, la actividad debe llamar a MarkCanceled. Las excepciones producidas desde este método son fatales para la instancia de flujo de trabajo.
protected override void Cancel(AsyncCodeActivityContext context)
{
// Implement any cleanup as a result of the asynchronous work
// being canceled, and then call MarkCanceled.
if (context.IsCancellationRequested)
{
context.MarkCanceled();
}
}
Invocar métodos asincrónicos en una clase
Muchas de las clases de .NET Framework proporcionan funcionalidad asincrónica y esta funcionalidad se puede invocar de forma asincrónica mediante una AsyncCodeActivity actividad basada. En el ejemplo siguiente, se crea una actividad que crea de forma asincrónica un archivo mediante la FileStream clase .
public sealed class FileWriter : AsyncCodeActivity
{
public FileWriter()
: base()
{
}
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
string tempFileName = Path.GetTempFileName();
Console.WriteLine("Writing to file: " + tempFileName);
FileStream file = File.Open(tempFileName, FileMode.Create);
context.UserState = file;
byte[] bytes = UnicodeEncoding.Unicode.GetBytes("123456789");
return file.BeginWrite(bytes, 0, bytes.Length, callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
FileStream file = (FileStream)context.UserState;
try
{
file.EndWrite(result);
file.Flush();
}
finally
{
file.Close();
}
}
}
Estado de uso compartido entre los métodos BeginExecute y EndExecute
En el ejemplo anterior, se accedió al objeto FileStream creado en BeginExecute en EndExecute. Esto es posible porque la variable file se pasó en la propiedad AsyncCodeActivityContext.UserState en BeginExecute. Este es el método correcto para compartir el estado entre BeginExecute y EndExecute. Es incorrecto usar una variable miembro en la clase derivada (FileWriter en este caso) para compartir el estado entre BeginExecute y EndExecute porque varias instancias de actividad pueden hacer referencia al objeto de actividad. Si se intenta usar una variable miembro para compartir el estado, los valores de un ActivityInstance pueden sobrescribir o consumir valores de otro ActivityInstance.
Obtener acceso a los valores de argumento
El entorno de un AsyncCodeActivity consiste en los argumentos definidos en la actividad. Se puede acceder a estos argumentos desde las BeginExecute/EndExecute sobrescrituras mediante el parámetro AsyncCodeActivityContext. No se puede tener acceso a los argumentos en el delegado, pero los valores de argumento o cualquier otro dato deseado se pueden pasar al delegado mediante sus parámetros. En el ejemplo siguiente, se define una actividad de generación aleatoria de números que obtiene el límite superior inclusivo de su Max argumento. El valor del argumento se pasa al código asincrónico cuando se invoca al delegado.
public sealed class GenerateRandomMax : AsyncCodeActivity<int>
{
public InArgument<int> Max { get; set; }
static Random r = new Random();
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
// Create a delegate that references the method that implements
// the asynchronous work. Assign the delegate to the UserState,
// invoke the delegate, and return the resulting IAsyncResult.
Func<int, int> GetRandomDelegate = new Func<int, int>(GetRandom);
context.UserState = GetRandomDelegate;
return GetRandomDelegate.BeginInvoke(Max.Get(context), callback, state);
}
protected override int EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
// Get the delegate from the UserState and call EndInvoke
Func<int, int> GetRandomDelegate = (Func<int, int>)context.UserState;
return (int)GetRandomDelegate.EndInvoke(result);
}
int GetRandom(int max)
{
// This activity simulates taking a few moments
// to generate the random number. This code runs
// asynchronously with respect to the workflow thread.
Thread.Sleep(5000);
return r.Next(1, max + 1);
}
}
Programación de acciones o actividades secundarias mediante AsyncCodeActivity
AsyncCodeActivity Las actividades personalizadas derivadas proporcionan un método para realizar el trabajo de forma asincrónica con respecto al subproceso de flujo de trabajo, pero no proporcionan la capacidad de programar actividades o acciones secundarias. Sin embargo, el comportamiento asincrónico se puede incorporar con la programación de actividades secundarias a través de la composición. Se puede crear una actividad asincrónica y luego componerla con una actividad derivada Activity o NativeActivity para proporcionar un comportamiento asincrónico y la programación de actividades o acciones secundarias. Por ejemplo, se podría crear una actividad que derive de Activity y tenga como implementación un Sequence que contenga la actividad asincrónica, así como otras actividades que implementan la lógica de dicha actividad. Para obtener más ejemplos de redacción de actividades mediante Activity y NativeActivity, vea How to: Create an Activity and Activity Authoring Options.