Olá a todos,
Nesse post vamos demonstrar como podemos ter transações distribuídas utilizando serviços WCF sendo propagadas para chamadas de diversos métodos que podem pertencer a diferentes serviços. Esse cenário pode ser desenvolvido utilizando dois modelos: um proprietário do WCF para situações onde existirão somente serviços construídos nessas tecnologia e outro utilizando o protocolo WS-AT (WS Atomic Transaction), que é um protocolo de controle de transações compatível com diversas tecnologias para desenvolvimento de webservices.
A estrutura de transação do WCF (para os dois tipo de protocolos citados acima) utiliza o modelo presente a partir do .Net Framework 2.0, onde temos dois tipos de objetos: Transacion e TransactionScope. Nesse modelo de programação o desenvolvedor normalmente lida com o objeto TransactionScope pois a duração da transação e as operações transacionadas são determinadas pela vida desse tipo de objeto. Temos nesse tipo de objeto três propriedades básicas que podem ser configuradas: seu período de timeout (TransactionTimeout), seu nível de isolamento (TransactionIsolationLevel) e se ela será confirmada automaticamente ou não (TransactionAutoCompleteOnSessionClose).
Para um método de um serviço WCF pertencer a uma transação ele deve ser decorado com o atributo TransactionFlow, onde deve ser informado a obrigatoriedade ou não da transação. Essa configuração é informada a partir de um parâmetro, que pode assumir três valores diferentes, passado para o atributo. O valor Allowed indica que um método pode ou não pertencer a uma transação, desse modo quando a chamada desse método pertencer a uma transação as operações realizadas por ele também estarão no contexto da transação. Porém se a chamada não pertencer a uma transação o método será executado com suas operações não transacionadas. O valor NotAllowed informa que o método não será executado em contexto de transação, ou seja, mesmo que a chamada possua uma transação ativa as operações realizadas pelo método com esse valor não estarão no contexto dessa transação nem de qualquer outra. Por último o valor Mandatory obriga o método a possuir uma transação. Nessa configuração caso a chamada não possua uma transação ativa será iniciada uma nova transação com o escopo desse método.
Passaremos agora para o desenvolvimento do nosso exemplo. Nele teremos dois serviços WCF onde cada um possuirá um método que pode ser chamado no contexto de uma transação. Um dos métodos faz a inserção em um banco de dados enquanto o outro enviará uma mensagem para uma fila MSMQ. Demonstraremos então o funcionamento da transação distribuída utilizando mais de um recurso. Começaremos então criando uma fila transacional no MSMQ e uma tabela em um banco de dados no SQL Server.
O próximo passo é construir a estrutura para o código que será composta de um Windows Service para hospedar os serviços WCF e de uma aplicação do tipo Console que será o iniciador das chamadas, controlando a transação. Adicionados esses projetos na solução adicione dois serviços WCF no projeto do Windows Service e faça as alterações necessárias nesse projeto para subir os serviços. Nesse exemplo as configurações serão controladas a partir do arquivo app.config dos projetos.
Adicionados os dois serviços WCF no projeto do Windows Service vamos iniciar as configurações para que eles suportem chamadas em contexto de transação. O primeiro item a ser alterado é o contrato de cada serviço. Nele será adicionado o atributo TransactionFlow na definição do método, especificando o seu suporte a transações. Essa alteração deve ser realizada para os contratos dos dois serviços.
Após a alteração dos dois contratos devemos modificar também o código da sua implementação, adicionando o atributo TransactionScopeRequired para o método.
Basta agora alterarmos o arquivo app.config do Windows Service para termos nossos serviços WCF suportando transações. Nessa configuração será alterada a configuração do binding, passando o valor do atributo transactionFlow como true e informando essa configuração nos endpoints:
Vamos então terminar o código dos serviços, onde o primeiro fará a inserção no banco de dados e o segundo enviará uma mensagem para o MSMQ, ambos no contexto de uma transação:
Passaremos agora a desenvolver a chamada da aplicação que inicia essa transação. Nesse exemplo utilizamos um projeto do tipo Console Application, porém outros tipos de projetos podem ser utilizados. O primeiro passo é gerar os proxies dos serviços, para isso podemos iniciar a versão de Debug do Windows Service a partir de uma linha de comando, solicitando ao Visual Studio a geração dos proxies dos dois serviços. Após gerados os proxies basta criar um objeto do tipo TransactionScope e realizar as chamadas dos serviços durante o seu ciclo de vida, como demonstrado abaixo:
Temos então nosso exemplo pronto. Podemos iniciar o Windows Service para abrir os serviços. Em seguida execute a aplicação que inicia a transação e realiza as chamadas. Poderemos ver que ao final da execução será adicionado um registro na tabela e será enviada a mensagem para a fila. Vamos agora retirar o comentário da linha de código na aplicação console para forçar o disparo de uma exceção com o intuito de forçar o rollback da transação. Ao executar todo o ciclo novamente veremos que a exceção foi disparada e não foi incluído o registro na tabela nem enviada a mensagem para a fila. Como sempre adicionei o exemplo no meu Sky Drive com o nome WCF_Transacional.
Abraços a todos e até o próximo post.







