Как создать настраиваемого участника отслеживания

Отслеживание рабочих процессов обеспечивает видимость состояния выполнения рабочего процесса. Среда выполнения рабочего процесса отправляет записи отслеживания, описывающие события жизненного цикла рабочего процесса, события жизненного цикла действия, возобновления закладок и сбои. Эти записи отслеживания используются участниками отслеживания. Windows Workflow Foundation (WF) включает стандартный участник отслеживания, который записывает записи отслеживания в качестве событий трассировки событий Windows (ETW). Если это не отвечает заданным требованиям, то можно создать своего собственного участника отслеживания. На этом шаге учебника описывается, как создать настраиваемого участника отслеживания и профиль отслеживания, которые захватывают выходные данные действий WriteLine, чтобы их можно было показать пользователю.

Создание пользовательского участника отслеживания

  1. Щелкните правой кнопкой мыши NumberGuessWorkflowHost в Обозреватель решений и выберите "Добавить", "Класс". Введите StatusTrackingParticipant в поле "Имя" и нажмите кнопку "Добавить".

  2. Добавьте следующие инструкции using (или Imports) в начало файла с другими инструкциями using (или Imports).

    Imports System.Activities.Tracking  
    Imports System.IO  
    
    using System.Activities.Tracking;  
    using System.IO;  
    
  3. Измените класс StatusTrackingParticipant таким образом, чтобы он наследовался от класса TrackingParticipant.

    Public Class StatusTrackingParticipant  
        Inherits TrackingParticipant  
    
    End Class  
    
    class StatusTrackingParticipant : TrackingParticipant  
    {  
    }  
    
  4. Добавьте следующее переопределение метода Track. Существует несколько различных записей отслеживания. Нас интересуют только выходные данные действий WriteLine, которые содержатся в записях отслеживания действий. Если TrackingRecord является ActivityTrackingRecord для действия WriteLine, Text действия WriteLine добавляется в файл после InstanceId рабочего процесса. В этом руководстве файл сохраняется в текущей папке ведущего приложения.

    Protected Overrides Sub Track(record As TrackingRecord, timeout As TimeSpan)  
        Dim asr As ActivityStateRecord = TryCast(record, ActivityStateRecord)  
    
        If Not asr Is Nothing Then  
            If asr.State = ActivityStates.Executing And _  
            asr.Activity.TypeName = "System.Activities.Statements.WriteLine" Then  
    
                'Append the WriteLine output to the tracking  
                'file for this instance.  
                Using writer As StreamWriter = File.AppendText(record.InstanceId.ToString())  
                    writer.WriteLine(asr.Arguments("Text"))  
                    writer.Close()  
                End Using  
            End If  
        End If  
    End Sub  
    
    protected override void Track(TrackingRecord record, TimeSpan timeout)  
    {  
        ActivityStateRecord asr = record as ActivityStateRecord;  
    
        if (asr != null)  
        {  
            if (asr.State == ActivityStates.Executing &&  
                asr.Activity.TypeName == "System.Activities.Statements.WriteLine")  
            {  
                // Append the WriteLine output to the tracking  
                // file for this instance  
                using (StreamWriter writer = File.AppendText(record.InstanceId.ToString()))  
                {  
                    writer.WriteLine(asr.Arguments["Text"]);  
                    writer.Close();  
                }  
            }  
        }  
    }  
    

    Если профиль отслеживания не указан, используется профиль по умолчанию. Если используется профиль отслеживания по умолчанию, записи отслеживания создаются для всех ActivityStates. Поскольку нам нужно получить текст только один раз в течение жизненного цикла действия WriteLine, мы извлекаем текст только из состояния ActivityStates.Executing. Чтобы создать профиль отслеживания и зарегистрировать участника отслеживания, создается профиль отслеживания, указывающий, что создаются только WriteLineActivityStates.Executing записи отслеживания.

Создание профиля отслеживания и регистрация участника отслеживания

  1. Щелкните правой кнопкой мыши WorkflowHostForm в Обозреватель решений и выберите "Просмотреть код".

  2. Добавьте следующие инструкции using (или Imports) в начало файла с другими инструкциями using (или Imports).

    Imports System.Activities.Tracking  
    
    using System.Activities.Tracking;  
    
  3. Добавьте следующий код в ConfigureWorkflowApplication сразу после кода, добавляющего StringWriter к расширениям рабочего процесса, и перед обработчиками жизненного цикла рабочего процесса.

    'Add the custom tracking participant with a tracking profile  
    'that only emits tracking records for WriteLine activities.  
    Dim query As New ActivityStateQuery()  
    query.ActivityName = "WriteLine"  
    query.States.Add(ActivityStates.Executing)  
    query.Arguments.Add("Text")  
    
    Dim profile As New TrackingProfile()  
    profile.Queries.Add(query)  
    
    Dim stp As New StatusTrackingParticipant()  
    stp.TrackingProfile = profile  
    
    wfApp.Extensions.Add(stp)  
    
    // Add the custom tracking participant with a tracking profile  
    // that only emits tracking records for WriteLine activities.  
    StatusTrackingParticipant stp = new StatusTrackingParticipant  
    {  
        TrackingProfile = new TrackingProfile  
        {  
            Queries =
            {  
                new ActivityStateQuery  
                {  
                    ActivityName = "WriteLine",  
                    States = { ActivityStates.Executing },  
                    Arguments = { "Text" }  
                }  
            }  
        }  
    };  
    
    wfApp.Extensions.Add(stp);  
    

    Этот профиль отслеживания указывает, что только записи состояния действий WriteLine в состоянии Executing отправляются пользовательскому участнику отслеживания.

    После добавления кода запуск ConfigureWorkflowApplication будет выглядеть так, как показано в следующем примере.

    Private Sub ConfigureWorkflowApplication(wfApp As WorkflowApplication)  
        'Configure the persistence store.  
        wfApp.InstanceStore = store  
    
        'Add a StringWriter to the extensions. This captures the output  
        'from the WriteLine activities so we can display it in the form.  
        Dim sw As New StringWriter()  
        wfApp.Extensions.Add(sw)  
    
        'Add the custom tracking participant with a tracking profile  
        'that only emits tracking records for WriteLine activities.  
        Dim query As New ActivityStateQuery()  
        query.ActivityName = "WriteLine"  
        query.States.Add(ActivityStates.Executing)  
        query.Arguments.Add("Text")  
    
        Dim profile As New TrackingProfile()  
        profile.Queries.Add(query)  
    
        Dim stp As New StatusTrackingParticipant()  
        stp.TrackingProfile = profile  
    
        wfApp.Extensions.Add(stp)  
    
        'Workflow lifecycle handlers...  
    
    private void ConfigureWorkflowApplication(WorkflowApplication wfApp)  
    {  
        // Configure the persistence store.  
        wfApp.InstanceStore = store;  
    
        // Add a StringWriter to the extensions. This captures the output  
        // from the WriteLine activities so we can display it in the form.  
        StringWriter sw = new StringWriter();  
        wfApp.Extensions.Add(sw);  
    
        // Add the custom tracking participant with a tracking profile  
        // that only emits tracking records for WriteLine activities.  
        StatusTrackingParticipant stp = new StatusTrackingParticipant  
        {  
            TrackingProfile = new TrackingProfile  
            {  
                Queries =
                {  
                    new ActivityStateQuery  
                    {  
                        ActivityName = "WriteLine",  
                        States = { ActivityStates.Executing },  
                        Arguments = { "Text" }  
                    }  
                }  
            }  
        };  
    
        wfApp.Extensions.Add(stp);  
    
        // Workflow lifecycle handlers...  
    

Отображение сведений об отслеживании

  1. Щелкните правой кнопкой мыши WorkflowHostForm в Обозреватель решений и выберите "Просмотреть код".

  2. В обработчике InstanceId_SelectedIndexChanged добавьте следующий код сразу после кода очистки окна состояния.

    'If there is tracking data for this workflow, display it  
    'in the status window.  
    If File.Exists(WorkflowInstanceId.ToString()) Then  
        Dim status As String = File.ReadAllText(WorkflowInstanceId.ToString())  
        UpdateStatus(status)  
    End If  
    
    // If there is tracking data for this workflow, display it  
    // in the status window.  
    if (File.Exists(WorkflowInstanceId.ToString()))  
    {  
        string status = File.ReadAllText(WorkflowInstanceId.ToString());  
        UpdateStatus(status);  
    }  
    

    Если новый рабочий процесс выбран в списке рабочих процессов, записи отслеживания для этого рабочего процесса загружаются и отображаются в окне состояния. Ниже приведен полный пример обработчика InstanceId_SelectedIndexChanged.

    Private Sub InstanceId_SelectedIndexChanged(sender As Object, e As EventArgs) Handles InstanceId.SelectedIndexChanged  
        If InstanceId.SelectedIndex = -1 Then  
            Return  
        End If  
    
        'Clear the status window.  
        WorkflowStatus.Clear()  
    
        'If there is tracking data for this workflow, display it  
        'in the status window.  
        If File.Exists(WorkflowInstanceId.ToString()) Then  
            Dim status As String = File.ReadAllText(WorkflowInstanceId.ToString())  
            UpdateStatus(status)  
        End If  
    
        'Get the workflow version and display it.  
        'If the workflow is just starting then this info will not  
        'be available in the persistence store so do not try and retrieve it.  
        If Not WorkflowStarting Then  
            Dim instance As WorkflowApplicationInstance = _  
                WorkflowApplication.GetInstance(WorkflowInstanceId, store)  
    
            WorkflowVersion.Text = _  
                WorkflowVersionMap.GetIdentityDescription(instance.DefinitionIdentity)  
    
            'Unload the instance.  
            instance.Abandon()  
        End If  
    End Sub  
    
    private void InstanceId_SelectedIndexChanged(object sender, EventArgs e)  
    {  
        if (InstanceId.SelectedIndex == -1)  
        {  
            return;  
        }  
    
        // Clear the status window.  
        WorkflowStatus.Clear();  
    
        // If there is tracking data for this workflow, display it  
        // in the status window.  
        if (File.Exists(WorkflowInstanceId.ToString()))  
        {  
            string status = File.ReadAllText(WorkflowInstanceId.ToString());  
            UpdateStatus(status);  
        }  
    
        // Get the workflow version and display it.  
        // If the workflow is just starting then this info will not  
        // be available in the persistence store so do not try and retrieve it.  
        if (!WorkflowStarting)  
        {  
            WorkflowApplicationInstance instance =  
                WorkflowApplication.GetInstance(this.WorkflowInstanceId, store);  
    
            WorkflowVersion.Text =  
                WorkflowVersionMap.GetIdentityDescription(instance.DefinitionIdentity);  
    
            // Unload the instance.  
            instance.Abandon();  
        }  
    }  
    

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

  1. Нажмите клавиши Ctrl+Shift+B, чтобы создать приложение.

  2. Нажмите клавиши Ctrl+F5, чтобы запустить приложение.

  3. Выберите диапазон для угадываемой игры и типа рабочего процесса, который нужно запустить, и нажмите кнопку "Создать игру". Введите угадывание в поле "Угадывание " и нажмите кнопку "Перейти ", чтобы отправить свое предположение. Обратите внимание, что состояние рабочего процесса отображается в окне состояния. Этот результат получен из действий WriteLine. Переключитесь на другой рабочий процесс, выбрав один из поля со списком "Идентификатор экземпляра рабочего процесса" и обратите внимание, что состояние текущего рабочего процесса удалено. Переключитесь на предыдущий рабочий процесс и отметьте, что состояние восстановлено, как в следующем примере.

    Примечание.

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

    Please enter a number between 1 and 10
    Your guess is too high.
    Please enter a number between 1 and 10
    

    Примечание.

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

    Запишите идентификатор экземпляра рабочего процесса и доведите игру до конца.

  4. Откройте Windows Обозреватель и перейдите в папку NumberGuessWorkflowHost\bin\debug (или bin\release в зависимости от параметров проекта). Обратите внимание, что в дополнение к исполняемым файлам проекта существуют файлы с именами с идентификатором GUID. Определите файл, который соответствует идентификатору экземпляра рабочего процесса, завершенного на предыдущем шаге, и откройте его в Блокноте. Данные отслеживания содержат информацию, подобную следующим данным.

    Please enter a number between 1 and 10
    Your guess is too high.
    Please enter a number between 1 and 10
    Your guess is too high.
    Please enter a number between 1 and 10
    

    В дополнение к отсутствию догадок пользователя эти данные отслеживания не содержат сведения о последнем предположении рабочего процесса. Это происходит потому, что данные отслеживания состоят только из выходных данных WriteLine рабочего процесса, а последнее отображаемое сообщение выдается из обработчика Completed после завершения рабочего процесса. На следующем шаге руководства: размещение нескольких версий рабочего процесса параллельно, существующие WriteLine действия изменяются для отображения угадок пользователя, а также добавляется дополнительное WriteLine действие, отображающее окончательные результаты. После интеграции этих изменений: размещение нескольких версий рабочего процесса параллельно демонстрирует размещение нескольких версий рабочего процесса одновременно.