Asynchrone activiteiten maken in WF
AsyncCodeActivity biedt auteurs van activiteiten een basisklasse die afgeleide activiteiten in staat stelt asynchrone uitvoeringslogica te implementeren. Dit is handig voor aangepaste activiteiten die asynchroon werk moeten uitvoeren zonder de thread van de werkstroomplanner vast te houden en activiteiten te blokkeren die parallel kunnen worden uitgevoerd. In dit onderwerp vindt u een overzicht van het maken van aangepaste asynchrone activiteiten met behulp van AsyncCodeActivity.
AsyncCodeActivity gebruiken
System.Activities biedt auteurs van aangepaste activiteiten verschillende basisklassen voor verschillende vereisten voor het ontwerpen van activiteiten. Elke gebruiker heeft een bepaalde semantische en biedt een werkstroomauteur (en de activiteitsruntime) een bijbehorend contract. Een AsyncCodeActivity op basisactiviteit is een activiteit die asynchroon werk uitvoert ten opzichte van de scheduler-thread en waarvan de uitvoeringslogica wordt uitgedrukt in beheerde code. Als gevolg van asynchroon gaan, kan een AsyncCodeActivity niet-actief punt veroorzaken tijdens de uitvoering. Vanwege de vluchtige aard van asynchroon werk, AsyncCodeActivity wordt er altijd een no persistent blok gemaakt voor de duur van de uitvoering van de activiteit. Hiermee voorkomt u dat de werkstroomruntime het werkstroomexemplaren midden in het asynchrone werk persistent maakt, en voorkomt u ook dat het werkstroomexemplaren worden verwijderd terwijl de asynchrone code wordt uitgevoerd.
AsyncCodeActivity-methoden
Activiteiten die zijn afgeleid van AsyncCodeActivity , kunnen asynchrone uitvoeringslogica maken door de BeginExecute en EndExecute methoden met aangepaste code te overschrijven. Wanneer deze methoden worden aangeroepen door de runtime, worden deze methoden doorgegeven aan een AsyncCodeActivityContext. AsyncCodeActivityContext staat de auteur van de activiteit toe om gedeelde status te BeginExecute/ EndExecute bieden in de eigenschap van UserState de context. In het volgende voorbeeld genereert een GenerateRandom
activiteit asynchroon een willekeurig getal.
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);
}
}
De vorige voorbeeldactiviteit is afgeleid van AsyncCodeActivity<TResult>en heeft een verhoogde OutArgument<int>
naam Result
. De waarde die door de GetRandom
methode wordt geretourneerd, wordt geëxtraheerd en geretourneerd door de EndExecute onderdrukking en deze waarde wordt ingesteld als de Result
waarde. Asynchrone activiteiten die geen resultaat retourneren, moeten worden afgeleid van AsyncCodeActivity. In het volgende voorbeeld wordt een DisplayRandom
activiteit gedefinieerd die is afgeleid van AsyncCodeActivity. Deze activiteit is vergelijkbaar met de GetRandom
activiteit, maar in plaats van een resultaat te retourneren, wordt er een bericht naar de console weergegeven.
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: {0}", r.Next(1, 101));
}
}
Omdat er geen retourwaarde is, DisplayRandom
gebruikt u een Action in plaats van een Func<T,TResult> om de gedelegeerde aan te roepen en retourneert de gemachtigde geen waarde.
AsyncCodeActivity biedt ook een Cancel onderdrukking. Hoewel BeginExecute en EndExecute vereist onderdrukkingen zijn, Cancel is dit optioneel en kan deze worden overschreven, zodat de activiteit de openstaande asynchrone status kan opschonen wanneer deze wordt geannuleerd of afgebroken. Als opschonen mogelijk is en AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested
is true
, moet de activiteit worden aangeroepen MarkCanceled. Eventuele uitzonderingen die zijn opgetreden bij deze methode, zijn onherstelbare gevolgen voor het werkstroomexemplaren.
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();
}
}
Asynchrone methoden aanroepen in een klasse
Veel van de klassen in .NET Framework bieden asynchrone functionaliteit en deze functionaliteit kan asynchroon worden aangeroepen met behulp van een activiteit op basis van een AsyncCodeActivity activiteit. In het volgende voorbeeld wordt een activiteit gemaakt die asynchroon een bestand maakt met behulp van de FileStream klasse.
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();
}
}
}
Deelstatus tussen de Methoden BeginExecute en EndExecute
In het vorige voorbeeld is het FileStream object waarin is gemaakt BeginExecute , geopend in de EndExecute. Dit is mogelijk omdat de file
variabele is doorgegeven in de AsyncCodeActivityContext.UserState eigenschap in BeginExecute. Dit is de juiste methode voor het delen van de status tussen BeginExecute en EndExecute. Het is onjuist om een lidvariabele te gebruiken in de afgeleide klasse (FileWriter
in dit geval) om de status te delen tussen BeginExecute en EndExecute omdat naar het activiteitsobject kan worden verwezen door meerdere activiteitsexemplaren. Als u probeert een lidvariabele te gebruiken om de status te delen, kan dit resulteren in waarden van de ene ActivityInstance overschrijving of het verbruiken van waarden uit een andere ActivityInstance.
Argumentwaarden openen
De omgeving van een AsyncCodeActivity bestand bestaat uit de argumenten die zijn gedefinieerd voor de activiteit. Deze argumenten kunnen worden geopend vanaf de BeginExecute/EndExecute onderdrukkingen met behulp van de AsyncCodeActivityContext parameter. De argumenten kunnen niet worden geopend in de gemachtigde, maar de argumentwaarden of andere gewenste gegevens kunnen worden doorgegeven aan de gemachtigde met behulp van de parameters. In het volgende voorbeeld wordt een willekeurige activiteit voor het genereren van getallen gedefinieerd waarmee de inclusieve bovengrens van het Max
argument wordt opgehaald. De waarde van het argument wordt doorgegeven aan de asynchrone code wanneer de gemachtigde wordt aangeroepen.
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);
}
}
Acties of onderliggende activiteiten plannen met behulp van AsyncCodeActivity
AsyncCodeActivity afgeleide aangepaste activiteiten bieden een methode voor het asynchroon uitvoeren van werk met betrekking tot de werkstroomthread, maar bieden niet de mogelijkheid om onderliggende activiteiten of acties te plannen. Asynchroon gedrag kan echter worden opgenomen met het plannen van onderliggende activiteiten via samenstelling. Een asynchrone activiteit kan worden gemaakt en vervolgens samengesteld met een Activity of NativeActivity afgeleide activiteit om asynchroon gedrag en planning van onderliggende activiteiten of acties te bieden. Een activiteit kan bijvoorbeeld worden gemaakt die is afgeleid van Activityen die als implementatie een Sequence activiteit bevat die de asynchrone activiteit bevat, evenals de andere activiteiten die de logica van de activiteit implementeren. Zie Instructies voor het opstellen van activiteiten voor meer voorbeelden van het opstellen van activiteiten en het maken van opties voor het maken van activiteiten.NativeActivityActivity