Обзор рабочего потока Windows Workflow. Часть 4Источник: rsdn
Возврат результатов из рабочего потока Visual StudioДругим распространенным требованием, предъявляемым к рабочему потоку, является возврат выходных параметров - может быть, тех, что будут как-то использованы, а затем записаны в базу данных или другое постоянное хранилище. Поскольку рабочий поток выполняется исполняющей средой рабочего потока, вы не можете просто так вызвать рабочий поток, используя стандартный вызов метода - вы должны создать экземпляр рабочего потока, запустить его и затем ожидать завершения этого экземпляра. Когда рабочий поток завершается, исполняющая система рабочего потока возбуждает событие WorkflowCompleted. Оно сопровождается контекстной информацией о рабочем потоке, который только что завершился, и содержит выходные данные этого потока. Поэтому чтобы получить выходные параметры рабочего потока, вы должны предусмотреть обработчик события WorkflowCompleted, и этот обработчик может извлекать выходные параметры из рабочего потока. В следующем коде показан пример того, как это можно сделать.
Здесь мы присоединили делегат к событию WorkflowCompleted. Внутри него осуществляется проход по коллекции OutputParameters экземпляра класса WorkflowCompletedEventArgs, переданного делегату, и все выходные параметры отображаются на консоли. Эта коллекция содержит все общедоступные свойства рабочего потока. Нет никаких пометок специфических выходных параметров рабочего потока. Привязка параметров к действиямТеперь, когда вы узнали, как передавать параметры в рабочий поток, вам также понадобится посмотреть, как связать эти параметры с действиями. Это делается с помощью механизма, называемого привязкой (binding). В ранее определенном DaysOfWeekActivity имеется свойство Date, которое, как упоминалось ранее, может быть жестко закодировано либо привязано с другому значению внутри рабочего потока. Привязываемое свойство отображается в таблице свойств, в среде Visual Studio , как показано на рис. 41.17. Наличие пиктограммы синего цвета рядом с именем свойства говорит о том, что это привязываемое свойство.
Двойной щелчок на пиктограмме привязкивызовет диалог, показанный на рис. 41.18. Этот диалог позволит выбрать соответствующее свойство для привязки свойства Date. На рис. 41.18 выбрано свойство OrderDate рабочего потока (которое определено как обычное свойство .NET, как было показано ранее в одном из предыдущих фрагментов кода). Всякое привязываемое свойство может быть привязано либо к свойству рабочего потока, внутри которого определено действие, либо к свойству любого действия, относящегося к рабочему потоку, которое находится выше текущего действия.
Обратите внимание, что тип данных привязываемого свойства должен соответствовать типу данных того свойства, к которому осуществляется привязка - диалог не позволит вам связать несоответствующие типы. Мы повторим код свойства Date, чтобы показать, как работает привязка, а объяснения вы найдете в следующем абзаце.
Когда вы привязываете свойство в рабочем потоке, то "за кулисами" конструируется объект типа ActivityBind, и это и будет тем "значением", которое сохраняется внутри свойства зависимости. Поэтому средству set свойства будет передан объект типа ActivityBind, и он будет сохранен внутри словаря свойств для данного действия. Объект ActivityBind состоит из данных, описывающих действие, к которому выполняется привязка, и свойства данного действия, которое будет использовано во время выполнения. При чтении значения свойства вызывается метод GetValue объекта DependencyObject, и этот метод проверяет значение лежащего в основе свойства на предмет того, является ли оно объектом ActivityBind. Если это так, затем разрешается действие, к которому выполняется привязка, а затем читается реальное значение свойства из этого действия. Однако если привязанное значение имеет другой тип, тогда просто возвращается объект из метода GetValue(). Исполняющая среда рабочего потокаДля того чтобы запустить рабочий поток, необходимо создать экземпляр класса WorkflowRuntime. Обычно это делается один раз внутри вашего приложения, и этот объект обычно определен как статический член приложения, поэтому он доступен в приложении отовсюду. Когда вы запускаете исполняющую систему, она перезагружает все экземпляры рабочих потоков, которые существовали на момент последнего запуска приложения, посредством чтения этих экземпляров из постоянного хранилища. Здесь используется служба, называемая службой постоянства (persistence service), которую мы определим ниже. Исполняющая система содержит методы для конструирования экземпляров рабочих потоков - имеются шесть разных методов CreateWorkflow, которые могут быть использованы для этого, а кроме этого, исполняющая система также содержит методы для перезагрузки экземпляров и перечисления всех работающих экземпляров. Исполняющая система также поддерживает ряд событий, которые возбуждаются на протяжении жизни рабочего потока, такие как WorkflowCreated (возбуждается, когда конструируется новый экземпляр рабочего потока), WorkflowIdled (возбуждается, когда рабочий поток ожидает ввода, как в приведенном ранее примере обработки отчетов о расходах) и WorkflowCompleted (возбуждается при завершении рабочего потока). Службы рабочих потоковРабочий поток не существует сам по себе. Как показано в предыдущих разделах, рабочий поток выполняется внутри WorkflowRuntime, и эта исполняющая система предоставляет службы запущенным рабочим потокам. Служба - это любой класс, который может понадобиться во время выполнения рабочего потока. Есть некоторые стандартные службы, предоставляемые вашим потокам исполняющей системой, и вы по желанию можете конструировать свои собственные службы, которые будут применяться запущенными рабочими потоками. В настоящем разделе описываются две стандартных службы, предоставляемые исполняющей системой, и затем будет показано, как создавать свои собственные службы и некоторые экземпляры, когда это необходимо. Когда выполняется действие, ему передается некоторая контекстная информация в параметре ActivityExecutionStatus метода Execute.
Одним из доступных методов в этом контекстном параметре является GetService<T>. Как показано в следующем коде, он может использоваться для доступа к службе, прикрепленной к исполняющей среде рабочего потока Visual Studio .
Службы, развернутые в исполняющей среде, добавляются в нее до вызова метода StartRuntime; если вы попытаетесь добавить службу к исполняющей среде после ее запуска, то получите исключение. Для добавления служб к исполняющей среде предусмотрены два метода: вы можете конструировать службы в коде и затем добавлять их к исполняющей среде вызовом метода AddService, либо вы можете определить службы внутри конфигурационного файла приложения, и они будут автоматически сконструированы и добавлены к исполняющей среде. В следующем фрагменте кода показано, как добавлять службы во время выполнения в коде. Добавляемые службы описаны ниже в этом разделе.
Здесь конструируются экземпляр SqlWorkflowPersistenceService, который используется исполняющей средой для сохранения состояния рабочего потока, а также экземпляр SqlTrackingService, который записывает события, происходящие в рабочем потоке во время его работы. Чтобы создать службы с помощью конфигурационного файла приложения, нужно добавить соответствующий раздел-обработчик для исполняющей среды рабочего потока, после чего добавить службы в этот раздел:
Внутри конфигурационного файла вы добавляете обработчик секции WF (имя не имеет значения, но должно совпадать с именем, приведенным ниже в секции конфигурации), а затем создаете соответствующие элементы для этого раздела. Элемент <Services> может содержать произвольный список элементов, состоящих из типа .NET и параметров, передаваемых службе при ее конструировании исполняющей средой. Для чтения настроек из файла конфигурации приложения во время выполнения вызывается другой конструктор, как показано ниже:
Этот конструктор создает экземпляры каждой службы, определенной внутри конфигурационного файла, и добавляет их в коллекцию служб во время выполнения. В следующем разделе рассматриваются некоторые стандартные службы, доступные в WF. |