Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
AsyncCodeActivity Udostępnia autorom działań klasę bazową, która umożliwia wykonywanie działań pochodnych w celu zaimplementowania logiki wykonywania asynchronicznego. Jest to przydatne w przypadku działań niestandardowych, które muszą wykonywać asynchroniczną pracę bez przechowywania wątku harmonogramu przepływu pracy i blokowania wszelkich działań, które mogą być uruchamiane równolegle. Ten temat zawiera omówienie sposobu tworzenia niestandardowych działań asynchronicznych przy użyciu programu AsyncCodeActivity.
Korzystanie z funkcji AsyncCodeActivity
System.Activities Udostępnia autorom działań niestandardowych różne klasy bazowe dla różnych wymagań dotyczących tworzenia działań. Każdy z nich ma określoną semantykę i udostępniają autorowi przepływu pracy (i środowisku uruchomieniowemu aktywności) odpowiadający mu kontrakt. Działanie oparte na AsyncCodeActivity to działanie, które wykonuje pracę asynchronicznie w stosunku do wątku harmonogramu i którego logika wykonania jest wyrażona w kodzie zarządzanym. W wyniku przejścia na tryb asynchroniczny, element AsyncCodeActivity może spowodować wystąpienie bezczynnego punktu podczas wykonywania. Ze względu na nietrwały charakter pracy asynchronicznej, AsyncCodeActivity zawsze tworzy blok nietrwały na czas wykonywania działania. Zapobiega to temu, aby środowisko uruchomieniowe przepływu pracy utrwalało wystąpienie przepływu pracy w trakcie pracy asynchronicznej, a także uniemożliwia rozładowanie wystąpienia przepływu pracy podczas wykonywania kodu asynchronicznego.
Metody AsyncCodeActivity
Działania pochodzące z AsyncCodeActivity mogą tworzyć logikę wykonywania asynchronicznego przez zastąpienie metod BeginExecute i EndExecute kodem niestandardowym. Po wywołaniu przez środowisko uruchomieniowe te metody są przekazywane jako AsyncCodeActivityContext.
AsyncCodeActivityContextumożliwia autorowi działania udostępnianie stanu BeginExecute/ EndExecute we właściwości kontekstu.UserState W poniższym przykładzie, aktywność GenerateRandom generuje asynchronicznie losową liczbę.
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);
}
}
Poprzednie przykładowe działanie pochodzi z AsyncCodeActivity<TResult>, i ma podwyższony OutArgument<int> o nazwie Result. Wartość zwracana przez metodę GetRandom jest wyodrębniana i zwracana przez przesłonięcie EndExecute, a następnie ustawiana jako wartość Result. Działania asynchroniczne, które nie zwracają wyniku, powinny pochodzić z klasy AsyncCodeActivity. W poniższym przykładzie zdefiniowano DisplayRandom aktywność, która wywodzi się z AsyncCodeActivity. To działanie jest podobne do GetRandom działania, ale zamiast zwracać wynik, wyświetla komunikat do konsoli.
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)}");
}
}
Należy pamiętać, że ponieważ nie ma wartości zwracanej, DisplayRandom używa Action zamiast Func<T,TResult> do wywołania swojego delegata, a delegat nie zwraca żadnej wartości.
AsyncCodeActivity również zapewnia Cancel przesłonięcia. Chociaż BeginExecute i EndExecute są obowiązkowe nadpisania, Cancel jest opcjonalne i można je zastąpić, aby aktywność mogła wyczyścić swój zaległy stan asynchroniczny, gdy jest anulowana lub przerywana. Jeśli czyszczenie jest możliwe i AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested ma truewartość , działanie powinno wywołać metodę MarkCanceled. Wszelkie wyjątki, zgłoszone przez tę metodę, są śmiertelne dla instancji przepływu pracy.
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();
}
}
Wywoływanie metod asynchronicznych w klasie
Wiele klas w programie .NET Framework zapewnia funkcje asynchroniczne, a ta funkcja może być asynchronicznie wywoływana przy użyciu działania opartego AsyncCodeActivity . W poniższym przykładzie zostanie utworzone działanie, które asynchronicznie tworzy plik przy użyciu FileStream klasy .
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();
}
}
}
Udostępnianie stanu między metodami BeginExecute i EndExecute
W poprzednim przykładzie obiekt FileStream, który został utworzony w BeginExecute, został użyty w EndExecute. Jest to możliwe, ponieważ zmienna file została przekazana we AsyncCodeActivityContext.UserState właściwości w BeginExecute. Jest to prawidłowa metoda udostępniania stanu między BeginExecute i EndExecute. Niepoprawne jest użycie zmiennej składowej w klasie pochodnej (FileWriter w tym przypadku) do współużytkowania stanu między elementami BeginExecute i EndExecute dlatego, że obiekt działania może być przywołyny przez wiele wystąpień działań. Gdy próbujemy użyć zmiennej składowej do współdzielenia stanu, może to spowodować, że wartości z jednego ActivityInstance nadpisują lub zużywają wartości z innego ActivityInstance.
Uzyskiwanie dostępu do wartości argumentów
Środowisko obiektu AsyncCodeActivity składa się z argumentów zdefiniowanych w działaniu. Dostęp do tych argumentów można uzyskać z BeginExecute/EndExecute przesłonięć za pomocą parametru AsyncCodeActivityContext. Nie można uzyskać dostępu do argumentów w delegatzie, ale wartości argumentów lub inne żądane dane można przekazać do delegata przy użyciu jego parametrów. W poniższym przykładzie zdefiniowano losowe działanie generowania liczb, które uzyskuje górną granicę inkluzywną z argumentu Max . Wartość argumentu jest przekazywana do kodu asynchronicznego po wywołaniu delegata.
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);
}
}
Planowanie akcji lub działań podrzędnych przy użyciu AsyncCodeActivity
AsyncCodeActivity Pochodne działania niestandardowe zapewniają metodę wykonywania pracy asynchronicznie w odniesieniu do wątku przepływu pracy, ale nie umożliwiają harmonogramowania działań podrzędnych ani akcji. Jednak zachowanie asynchroniczne może być realizowane przez planowanie działań podrzędnych z użyciem kompozycji. Działanie asynchroniczne można utworzyć, a następnie zestawić z działaniem pochodnym Activity lub NativeActivity w celu zapewnienia asynchronicznego zachowania i planowania działań podrzędnych lub akcji. Na przykład można utworzyć działanie, które pochodzi z Activityelementu , i ma jako implementację Sequence zawierające działanie asynchroniczne, a także inne działania, które implementują logikę działania. Aby uzyskać więcej przykładów tworzenia aktywności przy użyciu Activity i NativeActivity, zobacz Jak utworzyć aktywność oraz Opcje tworzenia aktywności.