Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
AsyncCodeActivity ger aktivitetsförfattare en basklass att använda som gör det möjligt för härledda aktiviteter att implementera asynkron körningslogik. Detta är användbart för anpassade aktiviteter som måste utföra asynkront arbete utan att hålla i tråden för arbetsflödesschemaläggaren och blockera aktiviteter som kan köras parallellt. Det här avsnittet innehåller en översikt över hur du skapar anpassade asynkrona aktiviteter med hjälp av AsyncCodeActivity.
Använda AsyncCodeActivity
System.Activities tillhandahåller anpassade aktivitetsutmöjare med olika basklasser för olika krav på att skapa aktiviteter. Varje del har en specifik semantisk innebörd och ger en arbetsflödesutvecklare (och aktivitetskörningen) ett motsvarande kontrakt. En AsyncCodeActivity baserad aktivitet är en aktivitet som utför arbete asynkront i förhållande till scheduler-tråden och vars körningslogik uttrycks i hanterad kod. Genom att bli asynkront kan en AsyncCodeActivity resultera i en vilopunkt under körning. På grund av det asynkrona arbetets flyktiga natur skapar en AsyncCodeActivity alltid ett icke-beständigt block under hela aktivitetens körning. Detta förhindrar att körningen av arbetsflöde bevarar arbetsflödesinstansen under det asynkrona arbetet och förhindrar även att arbetsflödesinstansen avladdas medan den asynkrona koden körs.
AsyncCodeActivity-metoder
Aktiviteter som härleds från AsyncCodeActivity kan skapa asynkron körningslogik genom att åsidosätta metoderna BeginExecute och EndExecute med anpassad kod. När de anropas av runtime-miljön skickas dessa metoder en AsyncCodeActivityContext.
AsyncCodeActivityContext tillåter aktivitetsförfattaren att ange delat tillstånd BeginExecute/ EndExecute i kontextens UserState egenskap. I följande exempel genererar en GenerateRandom aktivitet ett slumpmässigt tal asynkront.
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);
}
}
Föregående exempelaktivitet härleds från AsyncCodeActivity<TResult>, och har ett förhöjt OutArgument<int> som heter Result. Värdet som returneras av metoden GetRandom extraheras och returneras av åsidosättningen EndExecute, och detta värde sätts som Result värde. Asynkrona aktiviteter som inte returnerar ett resultat bör härledas från AsyncCodeActivity. I följande exempel definieras en DisplayRandom aktivitet som härleds från AsyncCodeActivity. Den här aktiviteten liknar GetRandom aktiviteten, men i stället för att returnera ett resultat visas ett meddelande till konsolen.
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)}");
}
}
Observera att eftersom det inte finns något returvärde DisplayRandom använder en Action i stället för en Func<T,TResult> för att anropa dess ombud och ombudet returnerar inget värde.
AsyncCodeActivity ger också en Cancel överskrivning. Även om BeginExecute och EndExecute är obligatoriska åsidosättningar, är Cancel valfritt och kan åsidosättas så att aktiviteten kan rensa upp sin enastående asynkrona status när den avbryts eller avbrytas. Om rensning är möjligt och AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested är true, ska aktiviteten anropa MarkCanceled. Alla undantag som genereras från den här metoden är allvarliga för arbetsflödesinstansen.
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();
}
}
Anropa asynkrona metoder på en klass
Många av klasserna i .NET Framework tillhandahåller asynkrona funktioner och den här funktionen kan anropas asynkront med hjälp av en AsyncCodeActivity baserad aktivitet. I följande exempel skapas en aktivitet som asynkront skapar en fil med hjälp FileStream av klassen.
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();
}
}
}
Delningstillstånd mellan Metoderna BeginExecute och EndExecute
I föregående exempel användes objektet FileStream som skapades i BeginExecute i EndExecute. Detta är möjligt eftersom variabeln file skickades i AsyncCodeActivityContext.UserState egenskapen i BeginExecute. Det här är rätt metod för att dela tillstånd mellan BeginExecute och EndExecute. Det är felaktigt att använda en medlemsvariabel i den härledda klassen (FileWriter i det här fallet) för att dela tillstånd mellan BeginExecute och EndExecute eftersom aktivitetsobjektet kan refereras av flera aktivitetsinstanser. Om du försöker använda en medlemsvariabel för att dela tillstånd kan det resultera i att värden från ett ActivityInstance överskrivs eller förbrukas av värden från ett annat ActivityInstance.
Åtkomst till argumentvärden
Miljön för en AsyncCodeActivity består av argumenten som definierats för aktiviteten. Dessa argument kan nås från BeginExecute/EndExecute åsidosättningarna med hjälp av AsyncCodeActivityContext-parametern. Det går inte att komma åt argumenten i ombudet, men argumentvärdena eller andra önskade data kan skickas till ombudet med hjälp av dess parametrar. I följande exempel definieras en slumpmässig talgenereringsaktivitet som hämtar den inkluderande övre gränsen från argumentet Max . Värdet för argumentet skickas till den asynkrona koden när ombudet anropas.
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);
}
}
Schemaläggning av planeringsåtgärder eller de underordnade aktiviteterna med AsyncCodeActivity
AsyncCodeActivity härledda anpassade aktiviteter ger en metod för att utföra arbete asynkront med avseende på arbetsflödestråden, men ger inte möjlighet att schemalägga underordnade aktiviteter eller åtgärder. Asynkront beteende kan dock integreras genom schemaläggning av underordnade aktiviteter med hjälp av sammansättning. En asynkron aktivitet kan skapas och sedan kombineras med en Activity eller NativeActivity härledd aktivitet för att tillhandahålla asynkront beteende och schemaläggning av barnaktiviteter eller åtgärder. En aktivitet kan till exempel skapas som härleds från Activityoch har som implementering en Sequence som innehåller den asynkrona aktiviteten samt de andra aktiviteter som implementerar aktivitetens logik. Fler exempel på hur du skapar aktiviteter med hjälp av Activity och NativeActivity finns i Så här skapar du en aktivitet och Alternativ för aktivitetsskapande.