В этой статье быстро подробно описывается шаги, которые вам необходимы, чтобы включить поддержку Foundation Workflow Workflow Windows (WF) в ASP.NET (Classic или MVC). Давайте воспользуемся очень маленьким демонстрационным приложением, чтобы показать вам, как вы можете это сделать.
Интеграция WF в ASP.NET - это то, что мне пришлось сделать в последних нескольких проектах, над которыми я работал. Поэтому я подумал, что создаю небольшое применение, которое показывает вам минимум кода, необходимый для достижения этого. Давайте построим образец применения шаг за шагом ...
Замечание : эта статья не является учебником на WF. Требуется некоторое основное понимание WF.
Запустите Studio SQL Server Management Studio и создайте новую базу данных под названием «Рабочий процесс». Вам необходимо создать несколько таблиц и логики (сохраненные процедуры и тому подобное), чтобы поддерживать постоянство для WF. В каталоге "C: Windows Microsoft.net Framework v3.0 Windows Workflow Foundation SQL EN" Вы найдете 4 файла SQL. Выполнить следующие два в этом порядке:
Это создает две таблицы и 10 сохраненных процедур, которые необходимы для поддержки постоянства для WF в базе данных SQL Server. Теперь загрузите исходный код для этой статьи, извлеките его и выполните скрипт DDL.SQL. Этот сценарий создает одну таблицу, называемую клиентом.
Вы должны получить структуру базы данных, которая выглядит так:
Рисунок 1 - База данных рабочего процесса

Когда вы откроете пример решения этой статьи, вы найдете один проект библиотеки кода под названием «База данных». Все, что он содержит, - это файл классов LINQ в SQL, который содержит одну организацию, а именно клиент.
Рисунок 2 - Клиентский объект

Пример приложения позволяет вам создавать клиентов. Все, что вам нужно сделать, это войти в имя пользователя. После этого начинается новый рабочий процесс, и вы можете утвердить клиента, отвергнуть его или ничего не делать. Если вы не предпринимаете действия, клиент будет удален после определенного тайм -аута.
Рисунок 3 - Рабочий процесс

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

Я поместил этот рабочий процесс в отдельный проект.
Рисунок 5 - Решение

Когда StateInitializationActivity завершит выполнение рабочего процесса, выслушает одно из 3 возможных событий:
Мероприятие тайм -аута опирается на задержку. Вам не нужно уволить это событие самостоятельно, однако вы отвечаете за стрельбу по двум другим событиям. Поэтому я создал локальный сервис.
Листинг 1 - интерфейс icustomerservice
[ ExternalDataExchange ]
public interface ICustomerService
{
event EventHandler < ExternalDataEventArgs > Approved ;
event EventHandler < ExternalDataEventArgs > Rejected ;
}Вы можете зарегистрировать только одну реализацию для локального сервиса в среде выполнения рабочего процесса, и реализация для Customer Sens выглядит так:
Листинг 2 - Customerervice
public class CustomerService : ICustomerService
{
public event EventHandler < ExternalDataEventArgs > Approved ;
public event EventHandler < ExternalDataEventArgs > Rejected ;
private bool FireEvent ( EventHandler < ExternalDataEventArgs > theEvent , ExternalDataEventArgs args )
{ //...}
public bool OnApproved ( Guid instanceId )
{
return FireEvent ( Approved , new ExternalDataEventArgs ( instanceId ) ) ;
}
public bool OnRejected ( Guid instanceId )
{
return FireEvent ( Rejected , new ExternalDataEventArgs ( instanceId ) ) ;
}
}Эта локальная служба позволяет запустить утвержденное или отклоненное событие, указав идентификатор экземпляра (GUID) рабочего процесса, который вы хотите продолжить выполнение.
В создании, одобрении или отклонениях клиентов не так много логики, но я вкладывал все в это в классе Customer Manager. Методы являются самоэкспланирующими. Этот класс позволяет вам получить список всех клиентов, добавлять новых клиентов, утверждать, отклонить и удалять клиентов.
Листинг 3 - класс Customer Manager
public class CustomerManager
{
public IEnumerable < Customer > GetCustomers ( ) { //... }
public Customer GetCustomerById ( Guid customerId ) { //... }
public void ApproveCustomer ( Guid customerId ) { //... }
public void RejectCustomer ( Guid customerId ) { //... }
public void DeleteCustomer ( Guid customerId ) { //... }
public void AddCustomer ( Guid customerId , string userName ) { //... }
}Рабочий процесс использует этот тип Customer Manager для выполнения всей своей работы.
Вуаля, фонды заложены. Вы настраиваете базу данных, которая поддерживает постоянство WF, создала рабочий процесс для создания, одобрения и отклонения клиентов и создал локальный сервис, который поможет вам направить экземпляры рабочего процесса, что делать.
Теперь давайте создадим новое веб -приложение ASP.NET, которое поставит все это работать. Я придумал оригинальное имя «WebApplication» для проекта ASP.NET.
Рисунок 6 - Проект WebPplication

Сайт содержит только одну страницу с названием default.aspx. На этой странице отображается список клиентов, позволяет добавлять новых клиентов и утверждать или отклонять существующие.
Рисунок 7 - страница default.aspx

Давайте настроим веб -приложение так, чтобы оно поддерживает WF. Код конфигурации, показанный в этой статье, сокращен для читаемости. Загрузите образец исходный код для полной версии.
Откройте файл конфигурации приложения (web.config) и добавьте следующую строку в раздел ConfigSections.
< configSections >
<!-- ... -->
< section name = " WorkflowRuntime "
type = " System.Workflow.Runtime.Configuration.WorkflowRuntimeSection...etc. " />
</ configSections >Вам необходимо добавить эту строку к узлу ConfigSections, чтобы .NET знал, что он должен использовать тип рабочих процессов, чтобы прочитать следующий бит конфигурации, который вам необходимо добавить в узел конфигурации.
< WorkflowRuntime >
< CommonParameters >
< add name = " ConnectionString " value = " your connection string " />
</ CommonParameters >
< Services >
< add type = " System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService,...etc. "
useActiveTimers = " true " />
< add type = " System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService,...etc. "
UnloadOnIdle = " true " LoadIntervalSeconds = " 5 " />
</ Services >
</ WorkflowRuntime >Узел Workflowruntime загружает услуги ManualWorkFlowsEdulerService и SQLWorkFlowPersistencieservice для выполнения рабочего процесса. Вам необходимо загрузить SQLWorkFlowPersistenceservice, если вы хотите сохранить свои рабочие процессы, и для ASP.NET рекомендуется использовать ManualWorkFlowsChedUlerService вместо службы DefaultWorkFlowsChedUlerService.
Каждый экземпляр рабочего процесса выполняется в отдельном потоке. Время выполнения рабочего процесса управляет этим с помощью службы планировщика рабочего процесса. По умолчанию во время выполнения используется тип по умолчанию FlowschedulerService. Все экземпляры рабочего процесса выполняются асинхронно.
Для ASP.NET лучше всего использовать ручную кладку FLOSSCHEDERERService, потому что он позволяет синхронно запускать рабочие процессы. Время выполнения рабочего процесса использует вызову из приложения хоста в этом случае.
Это позволяет вам ждать ответа от рабочего процесса, прежде чем ASP.NET отправит ответ. Конечно, не разумно выполнять какие -либо давние задачи в ваших рабочих процессах в этом случае. (PS: Проверьте этот пост в блоге для получения дополнительной информации по этой теме.)
При использовании ручной работы FlowschedulerService убедитесь, что вы установили свойство UseActiveTimers на True. Если вы оставите этот настройка на значение по умолчанию false, то любые задержки не будут возобновлены автоматически после истечения срока действия. Если установлено в True, время выполнения рабочего процесса будет использовать таймер в памяти для периодической проверки на срок службы.
Теперь, когда ваше приложение было настроено на основу использования рабочего процесса, вам нужно размещать время выполнения рабочего процесса.
В asp.net идеальное место для этого находится в файле Global.asax. Просто добавьте следующий код в обработчик событий Application_start (...).
Листинг 4 - Global.asax Application_Start
protected void Application_Start ( object sender , EventArgs e )
{
WorkflowRuntime runtime = new WorkflowRuntime ( "WorkflowRuntime" ) ;
ExternalDataExchangeService exchangeService = new ExternalDataExchangeService ( ) ;
runtime . AddService ( exchangeService ) ;
CustomerService customerService = new CustomerService ( ) ;
exchangeService . AddService ( customerService ) ;
runtime . StartRuntime ( ) ;
Application [ "WorkflowRuntime" ] = runtime ;
}Создается новый экземпляр рабочего процесса, затем создается и добавляется ExternaldataExchangeService и добавляется во время выполнения. Далее мы создаем экземпляр нашего местного обслуживания Icustomerservice и добавляем его в экземпляр ExternaldataExchangeService. Наконец, время выполнения начинается и хранится в состоянии приложения.
Точно так же вам нужно остановить время выполнения рабочего процесса, когда приложение заканчивается, как показано в списке 5.
Листинг 5 - Global.asax Application_end
protected void Application_End ( object sender , EventArgs e )
{
WorkflowRuntime runtime = Application [ "WorkflowRuntime" ] as WorkflowRuntime ;
if ( runtime != null )
{
runtime . StopRuntime ( ) ;
runtime . Dispose ( ) ;
}
} Когда вы нажимаете кнопку «Добавить», вам нужно начать новый рабочий процесс. При использовании ручной работы FlowschedulerService вы находитесь в полном контроле над выполнением экземпляров рабочего процесса. В листинге 6 вы можете видеть, что вам нужно выполнить эти шаги:
Листинг 6 - Создайте нового клиента
WorkflowRuntime runtime = ( WorkflowRuntime ) Application [ "WorkflowRuntime" ] ;
Dictionary < string , object > arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "UserName" , txtUserName . Text . Trim ( ) ) ;
WorkflowInstance workflow = runtime . CreateWorkflow ( typeof ( CustomerApprovalWorkflow ) , arguments ) ;
workflow . Start ( ) ;
ManualWorkflowSchedulerService scheduler =
( ManualWorkflowSchedulerService ) runtime . GetService ( typeof ( ManualWorkflowSchedulerService ) ) ;
scheduler . RunWorkflow ( workflow . InstanceId ) ; После того, как вы создали клиента, вы можете одобрить или отклонить его учетную запись. Другими словами, вам нужно продолжить рабочий процесс, который был начат, когда вы создали его аккаунт.
Код, показанный в листинге 7, аналогичен кому листинга 6. Единственное отличие состоит в том, что вы должны получить экземпляр вашего локального сервиса (Customerervice) и назвать его одобренным (...) методом. Оспозимый метод запускает утвержденное событие. После успешной доставки вы можете указать планировщику продолжить запуск рабочего процесса.
Листинг 7 - утвердить клиента
WorkflowRuntime runtime = ( WorkflowRuntime ) Application [ "WorkflowRuntime" ] ;
ManualWorkflowSchedulerService scheduler =
( ManualWorkflowSchedulerService ) runtime . GetService ( typeof ( ManualWorkflowSchedulerService ) ) ;
CustomerService customerService = ( CustomerService ) runtime . GetService < ICustomerService > ( ) ;
if ( customerService . OnApproved ( customerId ) )
{
scheduler . RunWorkflow ( customerId ) ;
}Отказ от учетной записи клиента похож. Вам нужно только отправить отклоненное событие вместо утвержденного события. Если вы не предпринимаете меры, то задержка будет вызвана через одну минуту, а учетная запись клиента будет автоматически удалена.
И это все, что нужно.