Olá pessoal. Tudo certo?!
Windows workflow foundation permite o desenvolvimento de aplicações poderosas e altamente customizáveis.
A idéia fundamental é permitir a definição e execução de fluxos de atividades. Esses fluxos podem ter seu estado de execução persistidos e recuperados facilmente. Ou seja, os fluxos de atividades podem ter curta ou longa duração. Isso faz com que sejam opções interessantes quando temos a necessidade de orquestrar processos.
A definição de fluxos pode ocorrer de diversas formas. Entre elas, usando:
- um editor gráfico (presente no Visual Studio e que pode ser “embutido” em nossas aplicações);
- arquivos de configuração XML (XAML para ser mais preciso);
- diretamente no código.
No post de hoje – o primeiro de uma série – mostro os fundamentos para definição de workflows no código. Para mim, essa é a forma mais rápida (não a mais fácil) para definir fluxos.
Começando..
Workflows podem ser definidos facilmente em código. Para que isso seja possível, em qualquer tipo de projeto, basta adicionar uma referência para System.Activities. Para esse post, começo mostrando fluxos definidos em uma aplicação console. Observe:
using System;
using System.Activities;
using System.Activities.Statements;
namespace CodedWorkflows
{
class Program
{
static void Main(string[] args)
{
Console.Title = "Workflow demo";
new Program().Run();
Console.WriteLine("ENTER to exit...");
Console.ReadLine();
}
private void Run()
{
WorkflowInvoker.Invoke(CreateWorkflow());
}
private Activity CreateWorkflow()
{
return new Sequence();
}
}
}
O que podemos observear nesse código?!
- A execução de um fluxo é disparada, normalmente, pelo método estático Invoke da classe WorkflowInvoker;
- Um fluxo pode ser reduzido a uma única atividade (no nosso exemplo, uma pré-definida chamada Sequence).
Agora, vejamos uma definição de fluxo mais “interessante”:
private Activity CreateWorkflow1()
{
return new Sequence()
{
DisplayName = "Main Sequence",
Activities = {
new WriteLine()
{
DisplayName="HelloWorld",
Text="Hello, World from WF"
},
new WriteLine()
{
DisplayName="DisplayTime",
Text=string.Format("The time is: {0}", DateTime.Now)
}
}
};
}
Repare como podemos fazer uso de functional construction. Parecido com o que fazemos quando usamos LINQ to Xml.
Como pode perceber,
- cada atividade possui uma propriedade DisplayName. Ela é importante para identificar a etapa quando o ffluxo estiver em execução;
- o framework disponibiliza um conjunto rico de atividades pré-definidas (entre elas WriteLine), para que possamos utilizar em nossos fluxos.
Executando o fluxo, temos:
Perfeito.
Variáveis do fluxo
Como os fluxos podem ser persistidos durante a execução para, depois, serem recuperados e concluídos, é importante que exista uma forma especial para manipulação do estado. Observe:
private Activity CreateWorkflow2()
{
var currentHour = new Variable<int>("hour", DateTime.Now.Hour);
return new Sequence()
{
Variables = {
currentHour,
},
DisplayName = "Main Sequence",
Activities = {
new WriteLine()
{
DisplayName="HelloWorld",
Text="Hello, World from WF"
},
new WriteLine()
{
DisplayName="DisplayHour",
Text= new InArgument<string>(ctx => currentHour.Get(ctx).ToString())
}
}
};
}
Como indicado no código:
- WF define um tipo especial para designar as variáveis do fluxo;
- Variáveis podem conter, em sua definição, um nome e um valor default;
- Variáveis são “plugadas” no fluxo;
- Valores das variáveis são recuperados dentro de cada etapa como um argumento. Variáveis tem valor definido conforme o contexto.
Executando esse fluxo, temos:
Certo?
Condicionais
Não há como definir fluxos de atividades sem condicionais. Certo?! Observe:
private Activity CreateWorkflow3()
{
var currentHour = new Variable<int>("hour", DateTime.Now.Hour);
return new Sequence()
{
Variables = {
currentHour,
},
DisplayName = "Main Sequence",
Activities = {
new WriteLine()
{
DisplayName="HelloWorld",
Text="Hello, World from WF"
},
new WriteLine()
{
DisplayName="DisplayHour",
Text= new InArgument<string>(ctx => currentHour.Get(ctx).ToString())
},
new If()
{
DisplayName = "Conditional Greeting",
Condition=ExpressionServices.Convert<bool>( ctx =>
currentHour.Get(ctx) < 12),
Then = new WriteLine() { Text = "Good morning!" },
Else = new WriteLine() { Text = "Good afternoon" }
}
}
};
}
Vejamos:
- WF define atividades para execução de atividades – entre elas, If;
- Há uma classe utilitária, chamada ExpressionServices, que ajuda na execução de expressões (necessária para a condição);
- As propriedades Then e Else aceitam atividades, o que permite, inclusive, novas condicionais ou sequências complexas.
Loops
Tão importantes quanto condicionais, são os loops. Observe:
private Activity CreateWorkflow4()
{
var counter = new Variable<int>("counter", DateTime.Now.Hour);
return new Sequence()
{
Variables = {
counter,
},
DisplayName = "Main Sequence",
Activities = {
new WriteLine()
{
DisplayName="HelloWorld",
Text="Hello, World from WF"
},
new If()
{
DisplayName = "Conditional Greeting",
Condition=ExpressionServices.Convert<bool>( ctx =>
counter.Get(ctx) < 12),
Then = new WriteLine() { Text = "Good morning!" },
Else = new WriteLine() { Text = "Good afternoon" }
},
new While()
{
DisplayName="Until counter > 0",
Condition = ExpressionServices.Convert<bool>( ctx =>
counter.Get(ctx) > 0),
Body = new Sequence()
{
Activities =
{
new WriteLine()
{
Text = new InArgument<string>(ctx => counter.Get(ctx).ToString())
},
new Delay()
{
Duration = TimeSpan.FromSeconds(1)
},
new Assign<int>()
{
DisplayName = "Decrementing counter",
Value = new InArgument<int>(ctx =>
counter.Get(ctx) - 1),
To = new OutArgument<int>(counter)
}
}
}
}
}
};
}
Perceba:
- WF define uma atividades para execução de loops – entre elas, While;
- Podemos determinar uma atividade como “corpo” do loop, inclusive novas sequências (o que fizemos);
- As variáveis do fluxo podem ter seus valores modificados através de uma atividade de atribuição.
Executando o código, temos
Bacana, não?
Por agora, era isso.
![]()






Giovanni Bassi
14/01/2012
Não sei se vc vai chegar nesse ponto, Elemar, mas eu tenho um problema com o WF: ele me parece muito mais complicado que um bom código C# sem ele, mais direto. Mesmo nos casos de extensão, ainda me parece algo desnecessário…
O q vc acha?
elemarjr
14/01/2012
Giggio,
Se comparar um “fluxo” WF com código em C#, naturalmente o primeiro é bem mais complicado que o segundo. Entretanto, penso que essa comparação não seja válida pois o propósito dos dois é significativamente diferente.
WF permite que definamos processos com duração mais longa, que podem ser modificados sem alteração no código-fonte. Isso torna essa tecnologia perfeita para implantação, por exemplo de ciclos de aprovação de documento (como ocorre no Sharepoint). Ou ainda, para implementação de sistemas de regras (como ocorre no Microsoft CRM). Ou seja, propicia a construção de ambientes altamente configuráveis e focados no domínio dos processos de negócio.
Como arquitetos, podemos conceber sistemas de orquestração de processos para organizações. Podemos pensar em “atividades” mais robustas que podem fazer interfaces com outros sistemas (máquinas, software, pessoas). Além disso, essa percepção de fluxo pode ajudar na determinação de sistemas de indicadores (também ajustados aos clientes).
O que acha?
Giovanni Bassi
14/01/2012
Eu acho que ainda assim é complicado demais. Implementa rum workflow de longa duranção é algo razoavelmente trivial. Com uma abordagem de TDD, em algumas horas está pronto… e o código fica mais fácil de ler e entender… além de você estar livre de ter que seguir “o jeito do WF”.
Toda vez que implementei algo com WF caí na ideia de complexidade alta demais no final, desnecessária.
Talvez seja uma consideração interessante pra você fazer nos posts, talvez até mais pra frente, quando o pessoal tiver entendido um pouco mais.
elemarjr
14/01/2012
Concordo, em partes, com você.
A implementação de fluxos a partir de um arquivo de configuração não é, exatamente, algo trivial. Pelo menos, não no nível que o WF fornece. Da mesma forma que a manipulação de estado também não é.
Repare, considero a escrita de “Coded Workflows”, como mostrei hoje algo que não deve ser feito na prática. Optei por começar a série dessa forma para mostrar que, no fim, há apenas uma estrutura de objetos fazendo a mágica acontecer.
Agora, considerando a possibilidade de usar o editor do VS em nossos sistemas, para construção de fluxos de alto nível, começamos a delinear, com mais facilidade, as atividades de análise de processo e negócio. Isso permite a maximização do retorno para os expertises. É esse (e somente esse) o cenário onde vejo o WF brilhar. Nesses cenários, acho que a complexidade não fica desnecessariamente alta.
Vamos ver se, nos próximos posts, consigo trazer exemplos “real world”. Exatamente para promover a reflexão (extremamente válida) que você está indicando.
Andre Dias
14/01/2012
Elemar,
Já trabalhei muito com o WF quando o meu dia a dia era basicamente código. Hoje, ainda desenvolvo alguma coisa, mas apenas quando preciso customizar processos de build no Team Build.
Sem dúvida, é muito mais trabalhoso escrever um código de negócios usando o WF, porém existem cenários onde os benefícios compensam o trabalho adicional.
O primeiro cenário de utilização que vejo é onde os processos são extremamente complexos e que mudam constantemente, exemplo disso são sistemas financeiros e sistemas que dependem de regras de governo. E aí uma nova medida provisória, um incentivo fiscal, ou uma simples decisão estratégica para aumentar consumo / crédito pode ser o pesadelo de qualquer programador. Neste cenário, ter um “processo descrito, legível e executável” pode fazer uma grande diferença na implantação dessas novas regras.
Um outro cenário que eu gosto muito de utilizar o WF é quando precisamos deixar pessoas de negócios modificarem o comportamento do sistema. Uma vez precisei hostear o WF Designer fora do Visual Studio e criar diversas custom activities para permitir analistas de créditos modificarem o processo de liberação de crédito conforme necessidade. Os caras podiam mudar regras de aprovação, aumentar limite, enfim, podiam definir todo o comportamento de uma esteira de aprovação sem escrever uma linha de código. Imagine a agilidade que isso dá ao negócio?
Acredito que, como tudo nessa vida, o WF é mais uma ferramenta que temos para viabilizar negócios a partir da TI. Só precisamos encaixá-la em cenários adequados para ter o maior ROI possível.
elemarjr
14/01/2012
Concordo absolutamente.
Thiago Triunfo
14/01/2012
Elemar, excelente post cara, parabéns, estarei de olho nas próximas partes desta série de artigos sobre WF!
Atualmente trabalho em uma empresa do mercado financeiro que vem demandando e cada vez mais vai demandar projetos que com certeza irei usufruir bastante e terei uma ótima experiência a agregar a mais no que já conheço sobre WF.
Salve Giovani, acho que esta discussão rende mais… não? ahahahah!
A abordagem da discussão de vocês é muito interessante levando em consideração o que realmente foi citado, hoje muitas vezes em nossas aplicações que contemplam implementação com WF realmente chegamos há alguns pontos onde a necessidade de seguir com a implementação utilizando ele é realmente questionada …”Não seria mais prudente e eficiente implementar nossas próprias classes com esta finalidade?”
Neste caso subentendo que um WF é desenvolvido com uma finalidade definida, estabelecida, o foco é especificamente isto, garantir processos o conceitual do processo, a preocupação é especifica neste sentido. Concordo com o Giovani onde ele cita que muitas vezes chegamos a niveis de complexidade que o questionamento acima é levantado, mas será que não é a regra de negócios que estamos implementando que deveria ser questionada? Será que ela esta correta? Observando de um ponto de vista onde não temos um cenário tão critico e complexo de implementação, me pergunto realmente se muitas vezes implementar com uma classe própria não é mais apropriado e simples (custo x prazo).
Acho que a discussão pode nos levar realmente ao argumento de definição do que estamos implementando. Ficou claro este meu ponto de vista?
elemarjr
14/01/2012
Novamente, concordo bastante.
Penso que WF seja interessante onde desejamos oferecer opção “sem traumas” de customizar o processo de negócio.
Carlos dos Santos
14/01/2012
Excelente introdução ao WF. Parabéns pelo artigo Elemar!
Rafael Leonhardt (@MumHaBR)
15/01/2012
Um bom exemplo de uso do WF em processos automatizados é o TFS, onde usa para os templates de build automatizado e passível de configuração.
elemarjr
17/01/2012
muito bem lembrado!