Поделиться через


Как запустить рабочий процесс

Данный раздел относится к версии Windows Workflow Foundation 4.

Этот раздел продолжает руководство «Приступая к работе» для Windows Workflow Foundation и указывает порядок выполнения рабочего процесса, описанного в предыдущем руководстве Как создать рабочий процесс.

Dd489463.note(ru-ru,VS.100).gifПримечание
Каждый раздел в учебнике «Приступая к работе» построен на основе предыдущих разделов. Для изучения этого раздела необходимо сначала пройти руководства Как создать действие и Как создать рабочий процесс.

Открытие проекта узла рабочего процесса

  1. Откройте решение из предыдущего раздела Как создать рабочий процесс в среде Visual Studio 2010.

  2. В Solution Explorer дважды щелкните Program.cs или Module1.vb для вывода кода.

    Dd489463.Tip(ru-ru,VS.100).gifСовет.
    Если окно Обозреватель решений не отображается, в меню Вид выберите пункт Обозреватель решений.

    Поскольку этот проект был создан с помощью шаблона Консольное приложение рабочего процесса, Program.cs или Module1.vb содержит следующий базовый код размещения рабочего процесса.

    WorkflowInvoker.Invoke(New Workflow1())
    
    WorkflowInvoker.Invoke(new Workflow1());
    

    Этот созданный код размещения использует класс WorkflowInvoker. Класс WorkflowInvoker обеспечивает простой способ вызова рабочего процесса аналогично вызову метода и может использоваться только для рабочих процессов, не использующих сохраняемость. WorkflowApplication предоставляет улучшенную модель выполнения рабочих процессов, которая включает уведомления о событиях жизненного цикла, управление выполнением, возобновления закладок и сохраняемость. В этом примере используются закладки, а для размещения рабочего процесса используется WorkflowApplication. Добавьте инструкцию using или Imports в начало файла Program.cs или Module1.vb после существующих инструкций using или Imports.

    Imports System.Threading
    
    using System.Threading;
    

    Замените строку кода, использующую WorkflowInvoker, следующим базовым кодом размещения WorkflowApplication. Этот образец кода размещения показывает основные шаги по размещению и вызову рабочего процесса, но пока не обладает достаточной функциональностью для успешного выполнения рабочего процесса, описанного в данном разделе. В ходе следующих шагов этот базовый код модифицируется и добавляются дополнительные функции, пока приложение не будет полностью готово.

    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()
    
    AutoResetEvent syncEvent = new AutoResetEvent(false);
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1());
    
    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();
    

    Этот код создает объект WorkflowApplication, подписывается на три события из жизненного цикла рабочего процесса, начинает рабочий процесс вызовом Run, а затем ждет завершения рабочего процесса. После завершения рабочего процесса устанавливается AutoResetEvent и ведущее приложение завершает работу.

Настройка входных аргументов рабочего процесса

  1. Добавьте следующую инструкцию в начало файла Program.cs или Module1.vb после существующих инструкций using или Imports.

    Imports System.Collections.Generic
    
    using System.Collections.Generic;
    
  2. Замените строку кода, создающую новое WorkflowApplication, следующим кодом, который создает и передает словарь параметров рабочему процессу, когда процесс создается.

    Dim inputs As New Dictionary(Of String, Object)
    inputs.Add("MaxNumber", 100)
    
    Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
    
    var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), inputs);
    

    В этом словаре содержится один элемент с ключом MaxNumber. Ключи в словаре входных данных соответствуют входным аргументам в корневом действии рабочего процесса. Параметр MaxNumber используется рабочим процессом для определения верхней границы для созданного случайного числа.

Извлечение выходных аргументов рабочего процесса

  1. Модифицируйте обработчик Completed, чтобы извлечь и отобразить число ходов, использованных рабочим процессом.

    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.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
    {
        int Turns = Convert.ToInt32(e.Outputs["Turns"]);
        Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns);
    
        syncEvent.Set();
    };
    

Возобновление закладки

  1. Добавьте следующий код в начало метода Main сразу после существующего объявления AutoResetEvent.

    Dim idleEvent As New AutoResetEvent(False)
    
    AutoResetEvent idleEvent = new AutoResetEvent(false);
    
  2. Добавьте следующий обработчик Idle сразу после трех существующих обработчиков жизненного цикла процесса в Main.

    wfApp.Idle = _
        Sub(e As WorkflowApplicationIdleEventArgs)
            idleEvent.Set()
        End Sub
    
    wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
    {
        idleEvent.Set();
    };
    

    Каждый раз, когда рабочий процесс переходит в неактивный режим в ожидании следующего предположения, вызывается этот обработчик и устанавливается idleAction AutoResetEvent. Код на следующем этапе использует idleEvent и syncEvent, чтобы определить, ждет рабочий процесс следующего предположения или он завершился.

    Dd489463.note(ru-ru,VS.100).gifПримечание
    В этом примере ведущее приложение использует события автоматического сброса в обработчиках Completed и Idle, чтобы синхронизировать ведущее приложение с ходом выполнения рабочего процесса. Устанавливать блокировку и ждать неактивности рабочего процесса перед возобновлением закладки не обязательно, но в этом примере требуются события синхронизации, чтобы узел знал, завершен ли рабочий процесс, или он ждет дальнейшего ввода данных от пользователя с помощью Bookmark. Дополнительные сведения см. в разделе Закладки.

  3. Удалите вызов WaitOne, замените его кодом для сборки входных данных от пользователя и возобновите Bookmark.

    Удалите следующую строку кода.

    syncEvent.WaitOne()
    
    syncEvent.WaitOne();
    

    Замените ее следующим примером.

    ' 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
    
    // 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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out Guess))
            {
                Console.WriteLine("Please enter an integer.");
            }
            else
            {
                validEntry = true;
                wfApp.ResumeBookmark("EnterGuess", Guess);
            }
        }
    }
    

Построение и запуск приложения

  1. В Обозревателе решений щелкните правой кнопкой мыши WorkflowConsoleApplication1 и выберите команду Установить как запускаемый проект.

  2. Нажмите сочетание клавиш CTRL+F5 для создания и запуска приложения. Попробуйте угадать число с наименьшим числом попыток.

    Инструкции по добавлению сохраняемости к приложению рабочего процесса см. в следующем разделе Как создать и запустить длительно выполняющийся рабочий процесс.

Пример

Ниже приведен полный код для метода Main.

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
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 WorkflowApplication(new Workflow1(), inputs);

    wfApp.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.Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
    {
        Console.WriteLine(e.Reason);
        syncEvent.Set();
    };

    wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.UnhandledException.ToString());
        return UnhandledExceptionAction.Terminate;
    };

    wfApp.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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out Guess))
            {
                Console.WriteLine("Please enter an integer.");
            }
            else
            {
                validEntry = true;
                wfApp.ResumeBookmark("EnterGuess", Guess);
            }
        }
    }
}

См. также

Задачи

Как создать рабочий процесс
Как создать и запустить длительно выполняющийся рабочий процесс

Справочник

WorkflowApplication
Bookmark

Другие ресурсы

Программирование в Windows Workflow Foundation
Учебник по началу работы
Ожидание входных данных в рабочем процессе
Размещение рабочих процессов