Практическое руководство. Запуск рабочего процесса
Этот раздел продолжает учебник "Приступая к работе" для Windows Workflow Foundation и показывает, как создать узел рабочего процесса и выполнить рабочий процесс, описанный в предыдущем разделе How to: Create a Workflow .
Примечание.
Каждый раздел в учебнике «Приступая к работе» построен на основе предыдущих разделов. Для изучения этого раздела необходимо сначала пройти руководства How to: Create an Activity и How to: Create a Workflow.
Создание проекта узла рабочего процесса
Откройте решение из предыдущей инструкции . Создание раздела действий с помощью Visual Studio 2012.
Щелкните правой кнопкой мыши решение WF45GettingStartedTutorial в окне Обозреватель решений и выберите Добавить, Создать проект.
Совет
Если окно Обозреватель решений не отображается, в меню Вид выберите пункт Обозреватель решений .
В узле Установленные выберите пункты Visual C#и Рабочий процесс (или Visual Basicи Рабочий процесс).
Примечание.
В зависимости от того, какой язык программирования задан как основной в Visual Studio, узел Visual C# или Visual Basic может находиться в разделе Другие языки узла Установленные .
Убедитесь, что в раскрывающемся списке версий .NET Framework выбран пункт .NET Framework 4.5 . В списке Рабочий процесс выберите Консольное приложение рабочего процесса . Введите
NumberGuessWorkflowHost
в поле Имя и нажмите кнопку ОК. Будет создано начальное приложение рабочего процесса с базовой поддержкой размещения рабочего процесса. Этот базовый код размещения изменяется и используется для выполнения приложения рабочего процесса.Щелкните правой кнопкой мыши созданный проект NumberGuessWorkflowHost в обозревателе решений и выберите Добавить ссылку. Выберите Решение из списка Добавление ссылки , установите флажок рядом с NumberGuessWorkflowActivitiesи нажмите кнопку ОК.
Щелкните правой кнопкой мыши Workflow1.xaml в окне Обозреватель решений и выберите Удалить. Нажмите кнопку ОК для подтверждения.
Изменение кода размещения рабочего процесса
В Solution Explorer дважды щелкните Program.cs или Module1.vb для вывода кода.
Совет
Если окно Обозреватель решений не отображается, в меню Вид выберите пункт Обозреватель решений .
Поскольку этот проект был создан с помощью шаблона Консольное приложение рабочего процесса , Program.cs или Module1.vb содержит следующий базовый код размещения рабочего процесса.
' Create and cache the workflow definition. Dim workflow1 As Activity = New Workflow1() WorkflowInvoker.Invoke(workflow1)
// Create and cache the workflow definition. Activity workflow1 = new Workflow1(); WorkflowInvoker.Invoke(workflow1);
Этот код размещения использует WorkflowInvoker. WorkflowInvoker предоставляет простой способ вызова рабочего процесса аналогично вызову метода и может использоваться только для рабочих процессов, не использующих сохраняемость. WorkflowApplication предоставляет улучшенную модель выполнения рабочих процессов, которая включает уведомления о событиях жизненного цикла, управление выполнением, возобновление закладок и сохраняемость. В этом примере используются закладки, а для размещения рабочего процесса используется WorkflowApplication . Добавьте инструкцию
using
или Imports в начало файла Program.cs или Module1.vb после существующих инструкций using или Imports .Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
Замените строки кода, использующие WorkflowInvoker , следующим базовым кодом размещения WorkflowApplication . Этот образец кода размещения показывает основные шаги по размещению и вызову рабочего процесса, но пока не обладает достаточной функциональностью для успешного выполнения рабочего процесса, описанного в данном разделе. В ходе следующих шагов этот базовый код модифицируется и добавляются дополнительные функции, пока приложение не будет полностью готово.
Примечание.
В этих примерах
StateMachineNumberGuessWorkflow
SequentialNumberGuessWorkflow
FlowchartNumberGuessWorkflow
необходимо заменитьWorkflow1
или в зависимости от того, какой рабочий процесс выполнен в предыдущем руководстве. Создание рабочего процесса. Если не заменитьWorkflow1
, то при попытке создать или запустить рабочий процесс будут выданы ошибки сборки.AutoResetEvent syncEvent = new AutoResetEvent(false); WorkflowApplication wfApp = new WorkflowApplication(_wf); wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e) { syncEvent.Set(); }; wfApp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e) { Console.WriteLine(e.Reason); syncEvent.Set(); }; wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine(e.UnhandledException.ToString()); return UnhandledExceptionAction.Terminate; }; wfApp.Run(); syncEvent.WaitOne();
Dim syncEvent As New AutoResetEvent(False) Dim wfApp As New WorkflowApplication(New Workflow1()) wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) syncEvent.Set() End Sub wfApp.Aborted = Sub(e As WorkflowApplicationAbortedEventArgs) Console.WriteLine(e.Reason) syncEvent.Set() End Sub wfApp.OnUnhandledException = Function(e As WorkflowApplicationUnhandledExceptionEventArgs) Console.WriteLine(e.UnhandledException) Return UnhandledExceptionAction.Terminate End Function wfApp.Run() syncEvent.WaitOne()
Этот код создает объект WorkflowApplication, подписывается на три события из жизненного цикла рабочего процесса, начинает рабочий процесс вызовом Run, а затем ждет завершения рабочего процесса. После завершения рабочего процесса устанавливается AutoResetEvent и ведущее приложение завершает работу.
Настройка входных аргументов рабочего процесса
Добавьте следующую инструкцию в начало файла Program.cs или Module1.vb после существующих инструкций
using
илиImports
.Замените строку кода, создающую новое WorkflowApplication , следующим кодом, который создает и передает словарь параметров рабочему процессу, когда процесс создается.
Примечание.
Замените
Workflow1
в этих примерах наFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
илиStateMachineNumberGuessWorkflow
в зависимости от рабочего процесса, который вы выполнили на предыдущем шаге How to: Create a Workflow . Если не заменитьWorkflow1
, то при попытке создать или запустить рабочий процесс будут выданы ошибки сборки.var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
В этом словаре содержится один элемент с ключом
MaxNumber
. Ключи в словаре входных данных соответствуют входным аргументам в корневом действии рабочего процесса.MaxNumber
используется рабочим процессом для определения верхней границы случайного числа.
Извлечение выходных аргументов рабочего процесса
Модифицируйте обработчик Completed , чтобы извлечь и отобразить число ходов, использованных рабочим процессом.
Completed = delegate (WorkflowApplicationCompletedEventArgs e) { int Turns = Convert.ToInt32(e.Outputs["Turns"]); Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns); syncEvent.Set(); },
wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns")) Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns) syncEvent.Set() End Sub
Возобновление закладки
Добавьте следующий код в начало метода
Main
сразу после существующего объявления AutoResetEvent .AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
Добавьте следующий обработчик Idle сразу после трех существующих обработчиков жизненного цикла процесса в
Main
.Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
Каждый раз, когда рабочий процесс становится неактивным, ожидая следующего предположения, вызывается этот обработчик и
idleAction
AutoResetEvent устанавливается. Код на следующем этапе используетidleEvent
иsyncEvent
, чтобы определить, ждет рабочий процесс следующего предположения или он завершился.Примечание.
В этом примере ведущее приложение использует события автоматического сброса в обработчиках Completed и Idle , чтобы синхронизировать ведущее приложение с ходом выполнения рабочего процесса. Устанавливать блокировку и ждать неактивности рабочего процесса перед возобновлением закладки не обязательно, но в этом примере требуются события синхронизации, чтобы узел знал, завершен ли рабочий процесс, или он ждет дальнейшего ввода данных от пользователя с помощью Bookmark. Дополнительные сведения см. в разделе "Закладки".
Удалите вызов
WaitOne
, замените его кодом для сборки входных данных от пользователя и возобновите Bookmark.Удалите следующую строку кода.
syncEvent.WaitOne();
syncEvent.WaitOne()
Замените ее следующим примером.
// Loop until the workflow completes. WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent }; while (WaitHandle.WaitAny(handles) != 0) { // Gather the user input and resume the bookmark. bool validEntry = false; while (!validEntry) { if (!Int32.TryParse(Console.ReadLine(), out int Guess)) { Console.WriteLine("Please enter an integer."); } else { validEntry = true; wfApp.ResumeBookmark("EnterGuess", Guess); } } }
' Loop until the workflow completes. Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent} Do While WaitHandle.WaitAny(waitHandles) <> 0 'Gather the user input and resume the bookmark. Dim validEntry As Boolean = False Do While validEntry = False Dim Guess As Integer If Int32.TryParse(Console.ReadLine(), Guess) = False Then Console.WriteLine("Please enter an integer.") Else validEntry = True wfApp.ResumeBookmark("EnterGuess", Guess) End If Loop Loop
Построение и запуск приложения
Щелкните правой кнопкой мыши NumberGuessWorkflowHost в окне Обозреватель решений и выберите команду Установить как запускаемый проект.
Нажмите клавиши CTRL+F5 для сборки и запуска приложения. Попробуйте угадать число с наименьшим числом попыток.
Чтобы протестировать приложение с другим стилем рабочего процесса, замените
Workflow1
в коде, который создает WorkflowApplication , наFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
илиStateMachineNumberGuessWorkflow
в зависимости от того, какой стиль рабочего процесса нужен.var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
Инструкции по добавлению сохраняемости к приложению рабочего процесса см. в следующем разделе How to: Create and Run a Long Running Workflow.
Пример
Ниже приведен полный код для метода Main
.
Примечание.
Замените Workflow1
в этих примерах на FlowchartNumberGuessWorkflow
, SequentialNumberGuessWorkflow
или StateMachineNumberGuessWorkflow
в зависимости от рабочего процесса, который вы выполнили на предыдущем шаге How to: Create a Workflow . Если не заменить Workflow1
, то при попытке создать или запустить рабочий процесс будут выданы ошибки сборки.
static void Main(string[] args)
{
AutoResetEvent syncEvent = new AutoResetEvent(false);
AutoResetEvent idleEvent = new AutoResetEvent(false);
var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
WorkflowApplication wfApp = new(_wf, inputs)
{
Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
int Turns = Convert.ToInt32(e.Outputs["Turns"]);
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns);
syncEvent.Set();
},
Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
{
Console.WriteLine(e.Reason);
syncEvent.Set();
},
OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
},
Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
idleEvent.Set();
}
};
wfApp.Run();
// Loop until the workflow completes.
WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent };
while (WaitHandle.WaitAny(handles) != 0)
{
// Gather the user input and resume the bookmark.
bool validEntry = false;
while (!validEntry)
{
if (!Int32.TryParse(Console.ReadLine(), out int Guess))
{
Console.WriteLine("Please enter an integer.");
}
else
{
validEntry = true;
wfApp.ResumeBookmark("EnterGuess", Guess);
}
}
}
}
Sub Main()
Dim syncEvent As New AutoResetEvent(False)
Dim idleEvent As New AutoResetEvent(False)
Dim inputs As New Dictionary(Of String, Object)
inputs.Add("MaxNumber", 100)
Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
wfApp.Completed =
Sub(e As WorkflowApplicationCompletedEventArgs)
Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns"))
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns)
syncEvent.Set()
End Sub
wfApp.Aborted =
Sub(e As WorkflowApplicationAbortedEventArgs)
Console.WriteLine(e.Reason)
syncEvent.Set()
End Sub
wfApp.OnUnhandledException =
Function(e As WorkflowApplicationUnhandledExceptionEventArgs)
Console.WriteLine(e.UnhandledException)
Return UnhandledExceptionAction.Terminate
End Function
wfApp.Idle =
Sub(e As WorkflowApplicationIdleEventArgs)
idleEvent.Set()
End Sub
wfApp.Run()
' Loop until the workflow completes.
Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent}
Do While WaitHandle.WaitAny(waitHandles) <> 0
'Gather the user input and resume the bookmark.
Dim validEntry As Boolean = False
Do While validEntry = False
Dim Guess As Integer
If Int32.TryParse(Console.ReadLine(), Guess) = False Then
Console.WriteLine("Please enter an integer.")
Else
validEntry = True
wfApp.ResumeBookmark("EnterGuess", Guess)
End If
Loop
Loop
End Sub
См. также
- WorkflowApplication
- Bookmark
- Программирование в Windows Workflow Foundation
- Руководство по началу работы
- Практическое руководство. Создание рабочего процесса
- Практическое руководство. Создание и запуск длительно выполняемого рабочего процесса
- Ожидание входных данных в рабочем процессе
- Размещение рабочих процессов