Как создать настраиваемого участника отслеживания
Отслеживание рабочих процессов обеспечивает видимость состояния выполнения рабочего процесса. Среда выполнения рабочего процесса отправляет записи отслеживания, описывающие события жизненного цикла рабочего процесса, события жизненного цикла действия, возобновления закладок и сбои. Эти записи отслеживания используются участниками отслеживания. Windows Workflow Foundation (WF) включает стандартный участник отслеживания, который записывает записи отслеживания в качестве событий трассировки событий Windows (ETW). Если это не отвечает заданным требованиям, то можно создать своего собственного участника отслеживания. На этом шаге учебника описывается, как создать настраиваемого участника отслеживания и профиль отслеживания, которые захватывают выходные данные действий WriteLine
, чтобы их можно было показать пользователю.
Создание пользовательского участника отслеживания
Щелкните правой кнопкой мыши NumberGuessWorkflowHost в Обозреватель решений и выберите "Добавить", "Класс". Введите
StatusTrackingParticipant
в поле "Имя" и нажмите кнопку "Добавить".Добавьте следующие инструкции
using
(илиImports
) в начало файла с другими инструкциямиusing
(илиImports
).Imports System.Activities.Tracking Imports System.IO
using System.Activities.Tracking; using System.IO;
Измените класс
StatusTrackingParticipant
таким образом, чтобы он наследовался от классаTrackingParticipant
.Public Class StatusTrackingParticipant Inherits TrackingParticipant End Class
class StatusTrackingParticipant : TrackingParticipant { }
Добавьте следующее переопределение метода
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
. Чтобы создать профиль отслеживания и зарегистрировать участника отслеживания, создается профиль отслеживания, указывающий, что создаются толькоWriteLine
ActivityStates.Executing
записи отслеживания.
Создание профиля отслеживания и регистрация участника отслеживания
Щелкните правой кнопкой мыши WorkflowHostForm в Обозреватель решений и выберите "Просмотреть код".
Добавьте следующие инструкции
using
(илиImports
) в начало файла с другими инструкциямиusing
(илиImports
).Imports System.Activities.Tracking
using System.Activities.Tracking;
Добавьте следующий код в
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...
Отображение сведений об отслеживании
Щелкните правой кнопкой мыши WorkflowHostForm в Обозреватель решений и выберите "Просмотреть код".
В обработчике
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(); } }
Построение и запуск приложения
Нажмите клавиши Ctrl+Shift+B, чтобы создать приложение.
Нажмите клавиши Ctrl+F5, чтобы запустить приложение.
Выберите диапазон для угадываемой игры и типа рабочего процесса, который нужно запустить, и нажмите кнопку "Создать игру". Введите угадывание в поле "Угадывание " и нажмите кнопку "Перейти ", чтобы отправить свое предположение. Обратите внимание, что состояние рабочего процесса отображается в окне состояния. Этот результат получен из действий
WriteLine
. Переключитесь на другой рабочий процесс, выбрав один из поля со списком "Идентификатор экземпляра рабочего процесса" и обратите внимание, что состояние текущего рабочего процесса удалено. Переключитесь на предыдущий рабочий процесс и отметьте, что состояние восстановлено, как в следующем примере.Примечание.
Если перейти к рабочему процессу, который был запущен до включения отслеживания, состояние не отображается. Но если вы вводите дополнительные предположения, их состояние сохраняется, поскольку теперь отслеживание включено.
Please enter a number between 1 and 10 Your guess is too high. Please enter a number between 1 and 10
Примечание.
Эти сведения полезны для определения диапазона случайного числа, но они не содержат никаких данных о предыдущих предположениях. Эти сведения приведены на следующем шаге. Практическое руководство. Размещение нескольких версий рабочего процесса параллельно.
Запишите идентификатор экземпляра рабочего процесса и доведите игру до конца.
Откройте проводник 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
действие, отображающее окончательные результаты. После интеграции этих изменений: размещение нескольких версий рабочего процесса параллельно демонстрирует размещение нескольких версий рабочего процесса одновременно.