Elemar DEV

Tecnologia e desenvolvimento

Encaminhamento condicional de mensagens com Message Router (usando C#)

Olá pessoal. Tudo certo!?

Continuando nossas discussões sobre mensageria, minha proposta para esse post é discutir mais um importante pattern: Message Router.

O fundamento desse pattern consiste em transferir mensagens de uma determinada Queue para outras segundo um critério, sem alterar as mensagens. Sua aplicação é ampla. Podemos considerar esse pattern tanto em sistemas mais simples de mensageria (usando MSMQ, por exemplo), quanto em sistemas mais robustos (em ambientes no Windows Azure).

Esse pattern pode ser combinado com “Pipers And Filters” (apresentei implantação no post anterior).

Cenário mais simples: Transferência de Queue (um-para-um)

O cenário mais simples para um Message Router é a transferência de uma mensagem de uma Queue para outra.

image

O ícone que estou usando na ilustração foi sugerido no livro Enterprise Integration Patterns na descrição desse padrão. Eis a implementação simples:

using System;
using System.Messaging;

namespace MSMQ.MessageRouters
{
    public sealed class SimpleMessageRouter
    {
        readonly MessageQueue inputQueue;
        readonly MessageQueue outputQueue;

        public SimpleMessageRouter(MessageQueue input, MessageQueue output)
        {
            this.inputQueue = input;
            this.outputQueue = output;
        }

        public void Start()
        {
            this.inputQueue.ReceiveCompleted += OnReceiveCompleted;
            this.inputQueue.BeginReceive();
        }

        void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
        {
            var source = (MessageQueue)sender;
            var message = source.EndReceive(e.AsyncResult);
            this.outputQueue.Send(message);
            this.inputQueue.BeginReceive();
        }
    }
}

Esse pattern ajuda quando precisamos “ampliar” sistemas legados. Movimentando mensagens entre Queues, podemos compatibilizar/integrar sistemas que não compartilhem a mesma estrutura.

Direcionamento condicional (If-Else)

Em sistemas mais complexos, podemos desejar que mensagens sigam fluxos de processamento diferentes. Podemos considerar desvios de acordo com o conteúdo da própria mensagem ou conforme determinadas condições do ambiente. Em qualquer um desses cenários, podemos associar um predicado as mensagens que, de acordo com sua realização, encaminhe-as para Queues adequadas. Observe:

image

Aqui, a implementação em C#.

using System;
using System.Messaging;

namespace MSMQ.MessageRouters
{
    public sealed class IfMessageRouter
    {
        readonly MessageQueue inputQueue;
        readonly Predicate condition;
        readonly MessageQueue ifTrueQueue;
        readonly MessageQueue ifFalseQueue;

        public IfMessageRouter(MessageQueue input, 
            Predicate condition,
            MessageQueue ifTrue,
            MessageQueue ifFalse
            )
        {
            this.inputQueue = input;
            this.condition = condition;
            this.ifTrueQueue = ifTrue;
            this.ifFalseQueue = ifFalse;
        }

        public void Start()
        {
            this.inputQueue.ReceiveCompleted += OnReceiveCompleted;
            this.inputQueue.BeginReceive();
        }

        void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
        {
            var source = (MessageQueue)sender;
            var message = source.EndReceive(e.AsyncResult);

            if (this.condition(message))
                SendTrue(message);
            else
                SendFalse(message);

            this.inputQueue.BeginReceive();
        }

        void SendTrue(Message message)
        {
            if (this.ifTrueQueue != null)
                this.ifTrueQueue.Send(message);
        }

        void SendFalse(Message message)
        {
            if (this.ifFalseQueue != null)
                this.ifFalseQueue.Send(message);
        }
    }
}

Perfeito. Continuando na linha de exemplos que mostrei nos post anterior, adiciono um condicional para que apenas mensagens começando com “A” sejam encaminhadas. Observe:

using System;
using System.Messaging;

namespace MSMQ.MessageRouters
{
    class Program
    {
         static void Main(string[] args)
        {
            Console.Title = "If Message Router";

            Predicate startsWithA = (message) =>
            {
                message.Formatter = new XmlMessageFormatter(new[] { typeof(string) });
                return (((string)message.Body).StartsWith("A")) ;
            };

            new IfMessageRouter(
                GetMessageQueue(@".\private$\sample_queue"),
                startsWithA,
                GetMessageQueue(@".\private$\sample_transformed"),
                null
                ).Start();

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();
        }

        static MessageQueue GetMessageQueue(string name)
        {
            if (MessageQueue.Exists(name))
                return new MessageQueue(name);
           
            return MessageQueue.Create(name);
        }
    }
}

É um exemplo bem simples (lembre-se que mensagens raramente serão strings, como indicado aqui). Mas, dá para reproduzir facilmente.

Direcionamento condicional (Case)

Condicionals If-Else podem se tornar custosos. Principalmente, por poderem exigir etapas e Queues adicionais. A solução está em suportar Cases.

image

Agora, a implementação em C#:

using System;
using System.Messaging;
using System.Collections.Generic;

namespace MSMQ.MessageRouters
{
    public sealed class CaseMessageRouter
    {
        readonly MessageQueue inputQueue;
        readonly Func evaluationFunc;
        readonly Dictionary caseQueues;
        readonly MessageQueue defaultQueue;

        public CaseMessageRouter(
            MessageQueue input, 
            Func evaluationFunc,
            Dictionary caseQueues,
            MessageQueue defaultQueue
            )
        {
            this.inputQueue = input;
            this.evaluationFunc = evaluationFunc;
            this.caseQueues = caseQueues;
            this.defaultQueue = defaultQueue;
        }

        public void Start()
        {
            this.inputQueue.ReceiveCompleted += OnReceiveCompleted;
            this.inputQueue.BeginReceive();
        }

        void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
        {
            var source = (MessageQueue)sender;
            var message = source.EndReceive(e.AsyncResult);
            
            var key = this.evaluationFunc(message);

            if (this.caseQueues.ContainsKey(key))
                this.caseQueues[key].Send(message);
            else
                this.defaultQueue.Send(message);

            this.inputQueue.BeginReceive();
        }
    }
}

Era isso!

5 comentários em “Encaminhamento condicional de mensagens com Message Router (usando C#)

  1. Pingback: Promovendo compatibilidade com Message Translator (usando C#) « Elemar DEV

  2. Pingback: Garantindo desacoplamento com Message Endpoints « Elemar DEV

  3. Pingback: Implementando EIPs em .NET « Simples Assim

  4. Pingback: Implementando os EIPs em .NET « Simples Assim

  5. Pingback: Sobre a integração de aplicações através de mensageria « Elemar DEV

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às 27/01/2012 por em Post e marcado , , , , .

Estatísticas

  • 626,615 hits
%d blogueiros gostam disto: