Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
AsyncCodeActivity fournit aux auteurs d'activités une classe de base qui permet aux activités dérivées d'implémenter la logique d'exécution asynchrone. Les activités personnalisées peuvent ainsi effectuer un travail asynchrone sans maintenir le thread du service de planification de workflow. Elles peuvent également bloquer toute activité qui peut s'exécuter en parallèle. Cette rubrique fournit une vue d'ensemble de la méthode de création des activités asynchrones personnalisées à l'aide de l'objet AsyncCodeActivity.
Utilisation d'AsyncCodeActivity
L'objet System.Activities fournit aux auteurs d'activités personnalisées différentes classes de base pour différentes spécifications de création d'activité. Chacune possède une sémantique particulière et fournit à un auteur de workflow (et au runtime d'activité) un contrat correspondant. Une activité basée sur l'objet AsyncCodeActivity est une activité qui effectue le travail de façon asynchrone par rapport au thread du service de planification et dont la logique d'exécution est exprimée en code managé. Du fait qu'il devienne asynchrone, un objet AsyncCodeActivity peut induire un point inactif lors de l'exécution. En raison de la nature volatile du travail asynchrone, un objet AsyncCodeActivity crée toujours un bloc sans persistance pour la durée d’exécution de l’activité. Cela empêche le runtime du workflow de rendre persistante l'instance de workflow au milieu du travail asynchrone, et empêche également l'instance de workflow de se décharger lors de l'exécution du code asynchrone.
Méthodes AsyncCodeActivity
Les activités qui dérivent de l'objet AsyncCodeActivity peuvent créer la logique d'exécution asynchrone en substituant le code personnalisé aux méthodes BeginExecute et EndExecute. Une fois appelées par le runtime, un AsyncCodeActivityContext est passé à ces méthodes. AsyncCodeActivityContext permet à l’auteur de l’activité de fournir l’état partagé des méthodes BeginExecute/ EndExecute dans la propriété UserState du contexte. Dans l'exemple suivant, une activité GenerateRandom
génère un nombre aléatoire de façon asynchrone.
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);
}
}
L'exemple d'activité précédent dérive d'AsyncCodeActivity<TResult>, et comprend un OutArgument<int>
élevé nommé Result
. La valeur retournée par la méthode GetRandom
est extraite et retournée par la substitution EndExecute et cette valeur est définie comme valeur Result
. Les activités asynchrones qui ne retournent pas de résultat doivent dériver d'AsyncCodeActivity. Dans l'exemple suivant, une activité DisplayRandom
qui dérive d'AsyncCodeActivity est définie. Cette activité est semblable à l'activité GetRandom
, mais au lieu de retourner un résultat, elle affiche un message sur la console.
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)}");
}
}
Notez qu'étant donné qu'il n'y a pas de valeur de retour, DisplayRandom
utilise un Action au lieu d'un Func<T,TResult> pour appeler son délégué, et que le délégué ne retourne aucune valeur.
AsyncCodeActivity fournit également une substitution Cancel. Tandis que BeginExecute et EndExecute sont des substitutions obligatoires, Cancel est facultative et peut être substituée de sorte que l'activité puisse nettoyer son état asynchrone en attente lors de son annulation ou de son abandon. Si le nettoyage est possible et AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested
est true
, l'activité doit appeler la méthode MarkCanceled. Toute exception levée à partir de cette méthode est critique pour l'instance de workflow.
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();
}
}
Appel de méthodes asynchrones sur une classe
De nombreuses classes de .NET Framework fournissent les fonctionnalités asynchrones. Ces dernières peuvent être appelées de façon asynchrone à l’aide d’une activité basée sur AsyncCodeActivity. Dans l’exemple suivant, l’activité qui est générée crée un fichier de façon asynchrone à l’aide de la classe FileStream.
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();
}
}
}
Partager l'état entre les méthodes BeginExecute et EndExecute
Dans l'exemple précédent, l'objet FileStream créé dans BeginExecute était accessible dans le EndExecute. Cela s'avère possible, car la variable file
a été passée dans la propriété AsyncCodeActivityContext.UserState dans BeginExecute. Il s'agit de la méthode correcte pour partager l'état entre BeginExecute et EndExecute. Il est incorrect d'utiliser une variable membre dans la classe dérivée (FileWriter
dans ce cas) pour partager l'état entre BeginExecute et EndExecute, car l'objet activité peut être référencé par plusieurs instances d'activité. Toute tentative d'utilisation d'une variable membre pour partager l'état peut générer des valeurs d'un ActivityInstance qui remplacent ou consomment des valeurs d'un autre ActivityInstance.
Accès aux valeurs des arguments
L’environnement d’un objet AsyncCodeActivity se compose d’arguments définis sur l’activité. Le paramètre AsyncCodeActivityContext permet d’accéder à ces arguments à partir des substitutions BeginExecute/EndExecute. Il est impossible d’accéder aux arguments dans le délégué, mais les valeurs d’argument ou toutes autres données peuvent être passées dans celui-ci à l’aide de ses paramètres. L'exemple suivant consiste à définir une activité générant un nombre aléatoire qui obtient la limite supérieure inclusive de son argument Max
. La valeur de l’argument est passée dans le code asynchrone lors de l’appel du délégué.
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);
}
}
Planifier des actions ou des activités enfants à l'aide d'AsyncCodeActivity
Les activités personnalisées dérivées de AsyncCodeActivity fournissent une méthode pour effectuer des tâches de façon asynchrone par rapport au thread du workflow, mais ne permettent pas de planifier des activités ou des actions enfants. Toutefois, le comportement asynchrone peut être incorporé à la planification des activités enfants via la composition. Une activité asynchrone peut être créée, puis être composée d'une activité dérivée Activity ou NativeActivity pour fournir le comportement asynchrone et planifier des activités ou actions enfants. Par exemple, une activité peut être créée qui dérive de Activity, et qui a comme implémentation un Sequence contenant l'activité asynchrone, ainsi que les autres activités qui implémentent la logique de l'activité. Pour plus d’exemples de composition d’activités à l’aide de Activity et NativeActivity, consultez Procédure : Créer une activité et Options de création d’activités.