Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
AsyncCodeActivity предоставляет авторам действий базовый класс, который позволяет производным действиям реализовать асинхронную логику выполнения. Это полезно для пользовательских действий, которые должны выполнять асинхронную работу, не удерживая поток планировщика рабочих процессов и не мешая выполнению любых действий, способных выполняться параллельно. В этом разделе изложены основные сведения о создании пользовательских асинхронных действий с помощью AsyncCodeActivity.
Использование AsyncCodeActivity
System.Activities предоставляет авторам пользовательских действий различные базовые классы для соответствия различным требованиям создания действий. Каждый из них несет в себе определенную семантику и предоставляет автору рабочего процесса (и среде выполнения действия) соответствующий контракт. Основанная на AsyncCodeActivity деятельность — это деятельность, которая выполняет работу асинхронно относительно потока планировщика, и логика выполнения которой выражена в управляемом коде. В результате асинхронного AsyncCodeActivity выполнения может вызвать неактивную точку во время выполнения. Из-за нестабильной природы асинхронной работы AsyncCodeActivity всегда создается блок без сохранения на время выполнения активности. Это предотвращает сохранение экземпляра рабочего процесса в середине асинхронной работы, а также предотвращает выгрузку экземпляра рабочего процесса во время выполнения асинхронного кода.
Методы AsyncCodeActivity
Действия, производные от AsyncCodeActivity, могут создавать асинхронную логику выполнения, переопределяя методы BeginExecute и EndExecute с помощью пользовательского кода. При вызове средой выполнения этим методам передается AsyncCodeActivityContext.
AsyncCodeActivityContextпозволяет автору действий предоставлять общее состояние BeginExecute/ EndExecute в свойстве контекста.UserState В следующем примере GenerateRandom действие создает случайное число асинхронно.
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);
}
}
Предыдущий пример задания происходит от AsyncCodeActivity<TResult>, и имеет повышенное значение OutArgument<int>, названное Result. Значение GetRandom, возвращенное методом, извлекается и возвращается методом EndExecute, который его переопределяет, и затем устанавливается как значение Result. Асинхронные действия, которые не возвращают результат, должны быть производными от AsyncCodeActivity. В следующем примере определяется действие, DisplayRandom наследуемое от AsyncCodeActivity. Это действие похоже на действие GetRandom, но вместо того, чтобы возвращать результат, оно отображает сообщение в консоли.
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)}");
}
}
Обратите внимание, что поскольку возвращаемое значение отсутствует, DisplayRandom вместо вызова делегата Func<T,TResult> используетсяAction, а делегат не возвращает значения.
AsyncCodeActivity также предоставляет возможность Cancel переопределения. Хотя BeginExecute и EndExecute являются обязательными переопределениями, Cancel является необязательным и может быть переопределен, чтобы действие могло очистить свое оставшееся асинхронное состояние при отмене или прерывании. Если очистка возможна и AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested является true, действие должно вызываться MarkCanceled. Все исключения, вызванные этим методом, являются неустранимыми для экземпляра рабочего процесса.
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();
}
}
Вызов асинхронных методов в классе
Многие классы в .NET Framework предоставляют асинхронную функциональность, и её можно вызывать асинхронно с помощью действия на основе AsyncCodeActivity. В следующем примере создается действие, которое асинхронно создает файл с помощью 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();
}
}
}
Передача состояния между методами BeginExecute и EndExecute
В предыдущем примере объект FileStream, созданный в BeginExecute, был доступен в EndExecute. Это возможно, так как переменная file была передана в свойстве AsyncCodeActivityContext.UserState, в BeginExecute. Это правильный метод для совместного использования состояния между BeginExecute и EndExecute. Неправильно использовать переменную-член в производном классе (FileWriter в данном случае) для совместного использования состояния между BeginExecute и EndExecute, потому что объект активности может ссылаться на несколько экземпляров активности. Попытка использовать переменную-член для общего доступа к состоянию может привести к перезаписи значений из одного ActivityInstance или их использованию другим ActivityInstance.
Доступ к значениям аргументов
Среда AsyncCodeActivity состоит из аргументов, заданных для действия. К этим аргументам можно получить доступ из BeginExecute/EndExecute переопределений, используя параметр AsyncCodeActivityContext. Аргументы не могут быть доступны в делегате, но значения аргументов или любые другие нужные данные можно передать делегату с помощью его параметров. В следующем примере определяется действие по генерации случайных чисел, которое получает включающую верхнюю границу из аргумента Max. Значение аргумента передается в асинхронный код при вызове делегата.
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);
}
}
Планирование действий или дочерних процессов с помощью AsyncCodeActivity
AsyncCodeActivity Производные пользовательские действия предоставляют метод для асинхронной работы в отношении потока рабочего процесса, но не предоставляют возможность планировать дочерние действия или действия. Однако асинхронное поведение можно включить в планирование дочерних действий с помощью композиции. Асинхронное действие можно создать, а затем скомпоновать с с помощью Activity или производного действия NativeActivity, чтобы обеспечить асинхронное поведение и управление дочерними действиями или задачами. Например, действие может быть создано, которое является производным от Activityи имеет свою реализацию Sequence , содержащую асинхронное действие, а также другие действия, реализующие логику действия. Дополнительные примеры создания действий с использованием Activity и NativeActivity см. в разделах "Практическое руководство: создание действий" и "Варианты разработки действий".