quarta-feira, 12 de dezembro de 2012

MSMQ: Tutorial Básico

Conforme dito no post anterior, pretendo iniciar uma pequena série de posts sobre padrões de Arquitetura Orientada a Eventos -- EDA. A ideia desse post é mostrar o básico do básico com foco em como enviar e receber mensagens usando o MSMQ com C# para termos uma base para os padrões.

É importante ressaltar que foi intencional o nível de hard code e falta de abstração. Afinal, não quero nada abstrair aqui; quero mostrar o core da API .NET do MSMQ com C#.

Talvez o primeiro passo antes de discutir algum padrão de integração entre sistemas usando mensagens seja mostrar como se envia e recebe uma mensagem -- as operações mais elementares de um sistema de mensagens.



Pré-Requisitos

Para poder completar os passos seguintes, você precisa ter o MSMQ habilitado no Windows (ele é um recurso nativo do Windows) e o Visual Studio.


Prática

O primeiro passo é criarmos um projeto no Visual Studio do tipo class library em .NET 4 com o nome de Eip.Messages (adotei o prefixo Eip que significa Enterprise Integration Patterns, mas dê o nome que quiser). Esse projeto é como se fosse o nosso modelo canônico. Ou seja, é o modelo que é compartilhado pelas aplicações que participam da integração. É como se fosse um contrato.

Seria viável e mais simples enviar e receber objetos do tipo string ou outros primitivos, mas para uma ideia mais real (e legal) do que podemos fazer com sistemas de mensagem, vamos usar um tipo complexo em forma de interface.

Dentro desse projeto, declare uma interface IMyMessage.

public interface IMyMessage
{
 string Text { get; set; }
}

E a implemente como a seguir:

[Serializable]
public class MyMessageImpl
 : IMyMessage
{
 public MyMessageImpl(string text)
 {
  Text = text;
 }
 public string Text { get; set; }
}

Observação: Em um modelo canônico real, não faz sentido declarar e implementar uma interface no mesmo lugar. Cada aplicação participante poderia implementar da melhor forma ou poderia haver uma implementação padrão separada para possibilitar uma implementação personalizada. Este exemplo está dessa forma por motivos de praticidade e simplicidade.

O segundo passo é adicionarmos um novo projeto do tipo Console chamado Eip.Send à solução e adicionarmos referências a System.Messaging e ao projeto que acabamos de criar. Essa é a aplicação que enviará mensagens -- IMyMessage.


Cole o código à seguir dentro do método static void Main(string[] args).

Console.Title = "Send Endpoint";
Console.WindowHeight = 10;
Console.WindowWidth = 50;

MessageQueue sendQueue = new MessageQueue(@".\private$\my_queue");
   
while (true)
{
 Console.WriteLine("Entre com a mensagem a ser enviada:");
 string inputRequest = Console.ReadLine();

 if (inputRequest == "sair")
  break;

 IMyMessage myEncapsulatedMessage = new MyMessageImpl(inputRequest);

 Message sendMessage = new Message(myEncapsulatedMessage, new BinaryMessageFormatter());

 sendQueue.Send(sendMessage);
 
 Console.WriteLine("mensagem enviada...");
}

Criação de Filas

Antes que nossa aplicação funcione, precisamos criar a fila my_queue. No exemplo acima, estamos fazendo referência a uma fila local (.\) privada (private$) de nome my_queue. É perfeitamente normal criar filas através da aplicação, mas vale criar a fila pelo gerenciador do Windows para colocarmos um pé em questões administrativas da solução.

Para abrir o gerenciado do computador do Windows, execute compmgmt.msc e Uma janela como a seguir deve abrir.


Dê um clique com o botão direito do mouse sobre Private Queues abaixo de Message Queuing que fica dentro de Services and Applications. Escolha New e depois Private Queue. Entre com o nome my_queue mantendo o checkbox Transactional desabilitado e clique em Ok logo após.


Pronto, você acabou de criar uma fila privada não transacional. Se você achou um saco fazer isso, dê uma olhada na classe System.Messaging.MessageQueue e em seus métodos estáticos MessageQueue.ExistsMessageQueue.Create.

A aplicação que envia mensagens já está pronta para ser usada. Inicie-a para dar uma olhada. Ela pede que você entre com uma mensagem e a envia para a fila. Digite qualquer coisa (menos "sair") e dê um Enter.



Meio chato até agora, não? Vamos criar o terceiro projeto que também é do tipo Console com o nome de Eip.Receive e adicionar as mesmas referências do projeto anterior. Essa aplicação vai consumir as mensagens da fila my_queue. Assim como na aplicação anterior, cole o código à seguir dentro do método static void Main(string[] args).

Console.Title = "Receive Endpoint";
Console.WindowHeight = 10;
Console.WindowWidth = 70;

MessageQueue myQueue = new MessageQueue(@".\private$\my_queue");
myQueue.Formatter = new BinaryMessageFormatter();

Console.WriteLine("Aguardando mensagens...");

while (true)
{
 Message receivedMessage = myQueue.Receive();
 IMyMessage myEncapsulatedMessage = (IMyMessage)receivedMessage.Body;
 Console.WriteLine("Mensagem recebida: '{0}'", myEncapsulatedMessage.Text);
}

Uma forma que facilita iniciar as aplicações de forma independente é ir nas propriedades da solução (não projeto) e na opção Startup Project, selecionar Current Selection.


Dessa forma, basta selecionar o projeto e dar um CTRL+F5 ou F5 se quiser debugar. Experimente e faço-o sobre Eip.Receive. Você deve notar que a mensagem que digitamos em alguns passos anteriores vai aparecer na tela.


Conclusão

A parte mais interessante dessa solução é o desacoplamento, principalmente temporal. Quem envia a mensagem não sabe quem recebe, se recebe e quando recebe. E quem recebe a mensagem não sabe quem a enviou e quando a enviou. Faça alguns testes iniciando as aplicações ao mesmo tempo, uma antes da outra, apenas uma de cada vez, etc.


Nenhum comentário:

Postar um comentário