Este artigo detalha rapidamente as etapas que você precisa executar para permitir o suporte à Windows Workflow Foundation (WF) no ASP.NET (Classic ou MVC). Vamos usar um aplicativo de demonstração muito pequeno para mostrar como você pode fazer isso.
A integração do WF no ASP.NET é algo que eu tive que fazer nos últimos projetos em que trabalhei. Por isso, pensei em construir um pequeno aplicativo de amostra que mostra o mínimo de código necessário para conseguir isso. Vamos construir um aplicativo de amostra passo a passo ...
Observação : Este artigo não é uma cartilha no WF. É necessária alguma compreensão básica do WF.
Inicie o SQL Server Management Studio e crie um novo banco de dados chamado "Workflow". Você precisa criar algumas tabelas e lógica (procedimentos armazenados e outros) para apoiar a persistência do WF. No diretório "C: Windows Microsoft.net Framework V3.0 Windows Workflow Foundation Sql en" Você encontrará 4 arquivos SQL. Execute os dois seguintes nesta ordem:
Isso cria duas tabelas e 10 procedimentos armazenados necessários para apoiar a persistência do WF em um banco de dados do SQL Server. Agora faça o download do código -fonte deste artigo, extrai -o e execute o script DDL.SQL. Este script cria uma tabela chamada Cliente.
Você deve acabar com uma estrutura de banco de dados que se parece com o seguinte:
Figura 1 - Banco de dados do fluxo de trabalho

Ao abrir a solução de amostra deste artigo, você encontrará um projeto de biblioteca de código chamado "banco de dados". Tudo o que ele contém é um arquivo de classes LINQ para SQL que contém uma entidade, a saber, cliente.
Figura 2 - entidade do cliente

O aplicativo de amostra permite criar clientes. Tudo o que você precisa fazer é entrar em um nome de usuário. Depois, um novo fluxo de trabalho é iniciado e você pode optar por aprovar o cliente, rejeitá -lo ou não fazer nada. Se você não agir, o cliente será excluído após um certo tempo limite.
Figura 3 - o fluxo de trabalho

Nesta amostra, há um fluxo de trabalho da máquina de estado. Para esse fluxo de trabalho, você deve fornecer um estado inicial e completo. Como você pode ver na figura acima, ele contém apenas dois estados que são nomeados adequadamente.
Este fluxo de trabalho requer um parâmetro chamado nome de usuário. Quando chega no estado inicial, a ativividade de estadualização é executada e um novo cliente é criado e persistido na tabela de clientes. Por padrão, todos os clientes precisam de aprovação.
Figura 4 - Clientes aguardando aprovação

Eu coloquei esse fluxo de trabalho em um projeto separado.
Figura 5 - A solução

Quando a atividade do Stateinitialization terminar de executar o fluxo de trabalho, ouvirá um dos 3 eventos possíveis:
O evento de tempo limite depende de uma retarda. Você não precisa demitir esse evento, mas está encarregado de disparar os outros dois eventos. Por isso, criei um serviço local.
Listagem 1 - Interface ICUSTOMERSERVICE
[ ExternalDataExchange ]
public interface ICustomerService
{
event EventHandler < ExternalDataEventArgs > Approved ;
event EventHandler < ExternalDataEventArgs > Rejected ;
}Você só pode registrar uma implementação para um serviço local no tempo de execução do fluxo de trabalho e a implementação do CustomerService se parece com o seguinte:
Listagem 2 - CustomerService
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 ) ) ;
}
}Este serviço local permite acionar o evento aprovado ou rejeitado especificando o ID da instância (GUID) do fluxo de trabalho que deseja continuar executando.
Não há muita lógica envolvida na criação, aprovação ou rejeição dos clientes, mas eu coloquei tudo nisso na classe CustomerManager. Os métodos são auto-explicativos. Esta aula permite recuperar uma lista de todos os clientes, adicionar novos clientes, aprovar, rejeitar e excluir clientes.
Listagem 3 - CustomerManager Class
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 ) { //... }
}O fluxo de trabalho usa esse tipo de cliente para executar todo o seu trabalho.
Voila, as fundações são colocadas. Você configurou um banco de dados que suporta a persistência da WF, criou um fluxo de trabalho para criar, aprovar e rejeitar clientes e criou um serviço local que o ajudará a direcionar suas instâncias de fluxo de trabalho o que fazer.
Agora vamos criar um novo aplicativo da Web ASP.NET que colocará tudo isso para funcionar. Eu criei o nome original "WebApplication" para o projeto ASP.NET.
Figura 6 - Projeto de aplicação da web

O site contém apenas uma página chamada default.aspx. Esta página exibe uma lista de clientes, permite adicionar novos clientes e aprovar ou rejeitar os existentes.
Figura 7 - Página de default.aspx

Vamos configurar o aplicativo da web para que ele suporta WF. O código de configuração mostrado neste artigo é abreviado para legibilidade. Faça o download do código -fonte da amostra para a versão completa.
Abra o arquivo de configuração do seu aplicativo (web.config) e adicione a seguinte linha à seção ConfigSections.
< configSections >
<!-- ... -->
< section name = " WorkflowRuntime "
type = " System.Workflow.Runtime.Configuration.WorkflowRuntimeSection...etc. " />
</ configSections >Você precisa adicionar essa linha ao nó ConfigSections, para que o .NET saiba que deve usar o tipo de fluxo de trabalho que seção
< 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 >O nó WorkflowRuntime carrega os serviços ManualWorkFlowSchedulerService e SQLWorkFlowPersistEnces Service para o tempo de execução do fluxo de trabalho. Você deve carregar o SQLWorkFlowPerSistEncyService, se desejar persistir seus fluxos de trabalho e, para asp.net, é aconselhável usar o manualworkflowschedulerservice em vez do serviço de FlowWlowsChedulerService.
Cada instância do fluxo de trabalho é executada em um encadeamento separado. O tempo de execução do fluxo de trabalho gerencia isso usando um serviço de agendamento de fluxo de trabalho. Por padrão, o tempo de execução usa o tipo DefaultWorkFlowSchedulerService. Todas as instâncias de fluxo de trabalho são executadas de maneira assíncrona.
Para asp.net, é melhor usar o ManualWorkFlowsChedulerService, porque permite que você execute fluxos de trabalho de maneira síncrona. O tempo de execução do fluxo de trabalho usa o thread de chamada do aplicativo host neste caso.
Isso permite que você aguarde uma resposta do fluxo de trabalho antes do ASP.NET enviar uma resposta. É claro que não é aconselhável executar tarefas de longa duração em seus fluxos de trabalho neste caso. (PS: Confira esta postagem do blog para obter mais informações sobre este tópico.)
Ao usar a ManualWorkFlowsChedulerService, certifique -se de definir a propriedade USEACTIVETIMERS como TRUE. Se você deixar essa configuração definida para o valor padrão do FALSE, quaisquer atividades de atraso não serão retomadas automaticamente após o expiração. Se definido como True, o tempo de execução do fluxo de trabalho usará um timer na memória para verificar periodicamente se há atrasos expirados.
Agora que seu aplicativo foi configurado para a Fundação de Uso Workflow, você precisa hospedar o tempo de execução do fluxo de trabalho.
No ASP.NET, o local ideal para fazer isso está no arquivo global.asax. Basta adicionar o código a seguir ao manipulador de eventos Application_Start (...).
Listagem 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 ;
}Uma nova instância do fluxo de trabalho é criada, então o ExternalDataExChangeService é criado e adicionado ao tempo de execução. Em seguida, criamos uma instância do nosso serviço local ICUSTOMERSERVICE e a adicionamos à instância do ExternalDataExChangeService. Finalmente, o tempo de execução é iniciado e armazenado no estado do aplicativo.
Da mesma forma, você precisa interromper o tempo de execução do fluxo de trabalho quando o aplicativo termina, conforme mostrado na Listagem 5.
Listagem 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 ( ) ;
}
} Ao clicar no botão Adicionar, você precisa iniciar um novo fluxo de trabalho. Ao usar o manualworkflowschedulerservice, você está no controle total da execução de suas instâncias de fluxo de trabalho. Na Listagem 6, você pode ver que precisa seguir estas etapas:
Listagem 6 - Crie um novo cliente
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 ) ; Depois de criar um cliente, você pode aprovar ou rejeitar a conta dele. Em outras palavras, você precisa continuar o fluxo de trabalho que foi iniciado quando criou a conta dele.
O código mostrado na Listagem 7 é semelhante ao da Listagem 6. A única diferença é que você deve recuperar a instância do seu serviço local (CustomerService) e chamá -lo está no método (...). O método On aprovado desencadeia o evento aprovado. Após a entrega bem -sucedida, você pode instruir o agendador a continuar executando o fluxo de trabalho.
Listagem 7 - Aprovar um cliente
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 ) ;
}Rejeitar a conta de um cliente é semelhante. Você só precisa enviar o evento rejeitado em vez do evento aprovado. Se você não tomar medidas, a ATEWATIVIDADE será acionada após um minuto e a conta do cliente será excluída automaticamente.
E isso é tudo o que há para isso.