Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
AsyncCodeActivity stellt Aktivitätsautoren eine Basisklasse bereit, die es abgeleiteten Aktivitäten ermöglicht, asynchrone Ausführungslogik zu implementieren. Dies ist nützlich für benutzerdefinierte Aktivitäten, die asynchrone Arbeit ausführen müssen, ohne den Workflowplanerthread zu blockieren und potenziell parallel ausführbare Aktivitäten zu behindern. Dieses Thema enthält eine Übersicht über das Erstellen von benutzerdefinierten asynchronen Aktivitäten mithilfe von AsyncCodeActivity.
Verwenden von AsyncCodeActivity
System.Activities stellt Autoren benutzerdefinierter Aktivitäten verschiedene Basisklassen für unterschiedliche Anforderungen an die Erstellung von Aktivitäten bereit. Jeder trägt eine bestimmte Semantik und bietet einem Workflow-Autor (und die Aktivitätslaufzeitumgebung) einen entsprechenden Vertrag. Eine AsyncCodeActivity basierte Aktivität ist eine Aktivität, die asynchron im Verhältnis zum Planerthread funktioniert und deren Ausführungslogik in verwaltetem Code ausgedrückt wird. Aufgrund des asynchronen Ablaufs kann ein AsyncCodeActivity einen Leerlauf während der Ausführung erzeugen. Aufgrund der flüchtigen Natur der asynchronen Arbeit erstellt ein AsyncCodeActivity immer einen nicht persistierenden Block für die Dauer der Ausführung der Aktivität. Dadurch wird verhindert, dass die Workflow-Laufzeit die Workflowinstanz in der Mitte des asynchronen Vorgangs speichert, und verhindert, dass die Workflowinstanz entladen wird, während der asynchrone Code ausgeführt wird.
AsyncCodeActivity-Methoden
Aktivitäten, die von AsyncCodeActivity abgeleitet werden, können asynchrone Ausführungslogik erstellen, indem die BeginExecute-Methode und die EndExecute-Methode mit benutzerdefiniertem Code überschrieben werden. Wenn sie von der Laufzeit aufgerufen werden, werden diesen Methoden ein AsyncCodeActivityContext übergeben.
AsyncCodeActivityContext ermöglicht dem Aktivitätsautor, den gemeinsamen Zustand BeginExecute/ EndExecute in der Eigenschaft des Kontextes UserState bereitzustellen. Im folgenden Beispiel generiert eine GenerateRandom Aktivität asynchron eine Zufallszahl.
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);
}
}
Die vorherige Beispielaktivität leitet sich von AsyncCodeActivity<TResult> ab und hat ein erhöhtes OutArgument<int>, das Result genannt wird. Der von der GetRandom-Methode zurückgegebene Wert wird extrahiert und von der EndExecute-Überschreibung zurückgegeben. Dieser Wert wird dann als Result-Wert festgelegt. Asynchrone Aktivitäten, die kein Ergebnis zurückliefern, sollten von AsyncCodeActivity abgeleitet sein. Im folgenden Beispiel wird eine DisplayRandom-Aktivität definiert, die sich von AsyncCodeActivity ableitet. Diese Aktivität ähnelt der GetRandom Aktivität, aber anstatt ein Ergebnis zurückzugeben, wird eine Meldung an die Konsole angezeigt.
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)}");
}
}
Beachten Sie, dass DisplayRandom anstelle von Action verwendet wird, um seinen Delegaten aufzurufen, da kein Rückgabewert vorhanden ist, und der Delegat gibt keinen Wert zurück.
AsyncCodeActivity stellt außerdem eine Cancel Außerkraftsetzung bereit. Während BeginExecute und EndExecute erforderliche Außerkraftsetzungen sind, ist Cancel optional und kann überschrieben werden, damit die Aktivität ihren ausstehenden asynchronen Zustand bereinigen kann, wenn sie storniert oder abgebrochen wird. Wenn die Bereinigung möglich ist und AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequestedtrue ist, sollte die Aktivität MarkCanceled aufrufen. Ausnahmen, die von dieser Methode ausgelöst werden, sind für die Workflowinstanz schwerwiegend.
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();
}
}
Aufrufen asynchroner Methoden für eine Klasse
Viele der Klassen in .NET Framework bieten asynchrone Funktionen, und diese Funktionalität kann mithilfe einer AsyncCodeActivity basierten Aktivität asynchron aufgerufen werden. Im folgenden Beispiel wird eine Aktivität erstellt, mit der asynchron eine Datei mithilfe der FileStream Klasse erstellt wird.
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();
}
}
}
Zustandsteilung zwischen den Methoden "BeginExecute" und "EndExecute"
Im vorherigen Beispiel wurde das in BeginExecute erstellte FileStream-Objekt in EndExecute zugegriffen. Dies ist möglich, da die file Variable in der AsyncCodeActivityContext.UserState Eigenschaft in BeginExecute übergeben wurde. Dies ist die richtige Methode zum Teilen des Zustands zwischen BeginExecute und EndExecute. Es ist falsch, eine Membervariable in der abgeleiteten Klasse (FileWriter in diesem Fall) zu verwenden, um den Status zwischen BeginExecute und EndExecute zu teilen, weil das Aktivitätsobjekt von mehreren Aktivitätsinstanzen referenziert werden kann. Der Versuch, eine Membervariable zu verwenden, um den Zustand zu teilen, kann dazu führen, dass Werte aus einem ActivityInstance die Werte eines anderen ActivityInstance überschreiben oder konsumieren.
Zugreifen auf Argumentwerte
Die Umgebung einer AsyncCodeActivity Besteht aus den Argumenten, die für die Aktivität definiert sind. Auf diese Argumente kann über die BeginExecute/EndExecute Überschreibungen mithilfe des AsyncCodeActivityContext-Parameters zugegriffen werden. Auf die Argumente kann im Delegaten nicht zugegriffen werden, aber die Argumentwerte oder andere gewünschte Daten können mithilfe seiner Parameter an den Delegaten übergeben werden. Im folgenden Beispiel wird eine Aktivität zur Erzeugung einer Zufallszahl definiert, die die einschließende obere Grenze des Max Arguments abruft. Der Wert des Arguments wird an den asynchronen Code übergeben, wenn der Delegat aufgerufen wird.
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);
}
}
Planen von Aktionen oder untergeordneten Aktivitäten mit AsyncCodeActivity
AsyncCodeActivity abgeleitete benutzerdefinierte Aktivitäten bieten eine Methode, Arbeiten unabhängig vom Workflowthread asynchron auszuführen, ermöglichen jedoch nicht die Planung von untergeordneten Aktivitäten oder Aktionen. Asynchrones Verhalten kann jedoch durch die Terminplanung von untergeordneten Aktivitäten mittels Komposition integriert werden. Eine asynchrone Aktivität kann erstellt und dann mit einer Activity oder NativeActivity abgeleiteten Aktivität zusammengesetzt werden, um asynchrones Verhalten und die Planung von untergeordneten Aktivitäten oder Aktionen zu ermöglichen. Beispielsweise könnte eine Aktivität erstellt werden, die von Activity abgeleitet wird, und als Implementierung eine Sequence, die die asynchrone Aktivität enthält und die anderen Aktivitäten, die die Logik der Aktivität umsetzen. Weitere Beispiele für das Verfassen von Aktivitäten mit Activity und NativeActivity finden Sie unter Wie man: Eine Aktivität erstellt und Optionen zur Aktivitätserstellung.