SimpleServiceBus

image Hi, today I would like to share with you SimpleServiceBus solution. I created this because I want to combine my all previous experience in communication components and both Multi-Core and Multi-Threading knowledge. The main reason for make this solution was to create the same simple abstraction for communication In-Proc, In-Host, In-Net in exactly the same way. SimpleServiceBus was build as a combination of the 3 flavors 5 simple generic components Requester<ReqMsg>, Requester<ReqMsg, ResMsg>, Receiver<ReqMsg>, Receiver<ReqMsg, ResMsg>, Responder<ReqMsg, ResMsg>. Those components are needed to communicate. Messages are generic attributes (ReqMsg and ResMsg) for those components that have to implement IMessage interface. And that interface is empty to make solution simpler. I think it is very easy to use SimpleServiceBus and I will show you that. I did bunch of tests and first I want to show you results of integration tests. Later I will share with you results of the performance tests. After that I will show you usage examples of this solution.

image

As you can see I tested all possible combinations of the communication, both In-Proc (inside the process) and In-Host (between processes inside the host). In fact communication In-Host uses loopback IP addresses, but when code uses any outside IP address the same components are changed without touch and are able to communicate In-Net (between processes on different hosts) as well. Important thing is that when you are using communication inside 1 process you still get benefits because you have constant number of threads during the process run and all those threads are using all CPU cores, so you can simple scale your solution and turn it into pure Multi-Core application or Cloud backed service. OK, so let’s look how fast my solution is? It is not my final word, this is just the beginning start point.

image

Now it is a time for sharing with you code samples. I did that as 2 demo classes with declarations of communication components elements and with comments. I think you will like it. Use this code as a guide documentation. But keep in mind that each communication component have to be in separated class depending of the solution design you have. For best performance you can make them static but it is not the obligatory way. I used 1 class for In-Proc communication examples and 1 class for In-Host or In-Net communication examples. I used loopback IP addresses, but of course you can use them as external addresses for your network communication. Important thing is that only Requester kind of components have to open listeners TCP ports. And all of that components need to be accessible from outsie if you are building services in Cloud, remember to open on Firewall access to them. So, here there are code examples for you.

namespace SimpleServiceBusSandbox
{
    using System;
    using CodingByToDesign.SimpleServiceBus.Communication.Contracts;
    using CodingByToDesign.SimpleServiceBus.Communication;

    // This is definition of your message protocol
    // and you need put it in shared assembly for
    // all components that need to communicate.
    // Only requirement is to derive from IMessage,
    // thet interface is empty.
    public class MyMessageReq : IMessage
    {
        // this is example of entity content.
        public string Uri { get; set; }
        public DateTime TimeStampUtc { get; set; }
        public string HttpMethod { get; set; }
    }

    // This is exqmple response message with data.
    public class MyMessageRes : IMessage
    {
        // this is example of entity content.
        public string Data { get; set; }
    }

    class SimpleServiceBusDemoClassInProc
    {
        // recevier in-proc
        private static IReceiver<MyMessageReq> receiver1 =
            new Receiver<MyMessageReq>{RecieveAction = ReceiveMessage};
        
        // receiver in-proc receive method
        private static void ReceiveMessage(MyMessageReq message) {
            // do what you want with received messages here
        }

        // requester in-proc
        private static IRequester<MyMessageReq> requester1 =
            new Requester<MyMessageReq>();

        // in-proc send/request method
        private static void SendMessageAsync1()
        {
            // sending example message to any Receiver<MyMessageReq>
            requester1.RequestAsync(new MyMessageReq {
                Uri = new Uri("http://codingbytodesign.net"),
                TimeStampUtc = DateTime.UtcNow,
                HttpMethod = "GET"
            });
        }

        // receiver in-proc that can response but do not have to
        private static IReceiver<MyMessageReq, MyMessageRes> receiver2 =
            new Receiver<MyMessageReq, MyMessageRes>
            { RecieveAction = ReceiveMessage2 };

        // method that receive messages
        private static void ReceiveMessage2(TransactId id, MyMessageReq mesage)
        {
            // you can response back but you do not have to
            receiver2.ResponseAsync(id, new MyMessageRes
                                        { Data = "CodingByToDesign.NET" });
        }

        // requester in-proc that can get responses
        private static IRequester<MyMessageReq, MyMessageRes> requester2 =
            new Requester<MyMessageReq, MyMessageRes>
            { ResponseAction = ReceiveMessageBack2 };

        private static void ReceiveMessageBack2(MyMessageRes message) {
            // do what you want with received response messages here
        }

        // in-proc send/request method 2
        private static void SendMessageAsync2()
        {
            // sending example message
            requester2.RequestAsync(new MyMessageReq
            {
                Uri = new Uri("http://codingbytodesign.net"),
                TimeStampUtc = DateTime.UtcNow,
                HttpMethod = "GET"
            },
            // optional parameter if it is null ReceiveMessageBack2 will be used
            new Action<MyMessageRes>(
                msgRes => { /* use your response message here */ }));
        }

        // responder in-proc that have to respond always for messages
        private static IResponder<MyMessageReq, MyMessageRes> responder3 =
            new Responder<MyMessageReq, MyMessageRes>
            { ResponseFunc = RespondMessage };

        // method that receive messages and need to create respond message
        private static MyMessageRes RespondMessage(MyMessageReq message)
        {
            return new MyMessageRes { Data = "CodingByToDesign.NET" };
        }

        // requester in-proc that can get responses
        private static IRequester<MyMessageReq, MyMessageRes> requester3 =
            new Requester<MyMessageReq, MyMessageRes>
            { ResponseAction = ReceiveMessageBack3 };

        private static void ReceiveMessageBack3(MyMessageRes message)
        {
            // do what you want with received response messages here
        }

        // in-proc send/request method 3
        private static void SendMessageAsync3()
        {
            // sending example message
            requester3.RequestSync(new MyMessageReq
            {
                Uri = new Uri("http://codingbytodesign.net"),
                TimeStampUtc = DateTime.UtcNow,
                HttpMethod = "GET"
            },
            // optional parameter if it is null ReceiveMessageBack3 will be used
            new Action<MyMessageRes>(
                msgRes => { /* use your response message here */ }));
        }
    }

    class SimpleServiceBusDemoClassInHostOrInNet
    {
        // recevier in-host or in-net
        private static IReceiver<MyMessageReq> receiver1 =
            new Receiver<MyMessageReq>(
                netTcpRequesterAddress: "net.tcp://127.0.0.1:27271/Demo"
            ){ RecieveAction = ReceiveMessage };

        // receiver in-host or in-net receive method
        private static void ReceiveMessage(MyMessageReq message)
        {
            // do what you want with received messages here
        }

        // requester in-host or in-net
        private static IRequester<MyMessageReq> requester1 =
            new Requester<MyMessageReq>(
                netTcpRequesterAddress: "net.tcp://127.0.0.1:27271/Demo"
            );

        // receive in-host or in-net send/request method
        private static void SendMessageAsync1()
        {
            // sending example message to any Receiver<MyMessageReq>
            requester1.RequestAsync(new MyMessageReq
            {
                Uri = new Uri("http://codingbytodesign.net"),
                TimeStampUtc = DateTime.UtcNow,
                HttpMethod = "GET"
            });
        }

        // receiver in-host or in-net that can response but do not have to
        private static IReceiver<MyMessageReq, MyMessageRes> receiver2 =
            new Receiver<MyMessageReq, MyMessageRes>(
                netTcpRequesterAddress: "net.tcp://127.0.0.1:27272/Demo"
            ) { RecieveAction = ReceiveMessage2 };

        // method that receive messages
        private static void ReceiveMessage2(TransactId id, MyMessageReq mesage)
        {
            // you can response back but you do not have to
            receiver2.ResponseAsync(id, new MyMessageRes
                                        { Data = "CodingByToDesign.NET" });
        }

        // requester in-host or in-net that can get responses
        private static IRequester<MyMessageReq, MyMessageRes> requester2 =
            new Requester<MyMessageReq, MyMessageRes>(
                netTcpRequesterAddress: "net.tcp://127.0.0.1:27272/Demo"
            ) { ResponseAction = ReceiveMessageBack2 };

        private static void ReceiveMessageBack2(MyMessageRes message)
        {
            // do what you want with received response messages here
        }

        // in-host or in-net send/request method 2
        private static void SendMessageAsync2()
        {
            // sending example message
            requester2.RequestAsync(new MyMessageReq
            {
                Uri = new Uri("http://codingbytodesign.net"),
                TimeStampUtc = DateTime.UtcNow,
                HttpMethod = "GET"
            },
            // optional parameter if it is null ReceiveMessageBack2 will be used
            new Action<MyMessageRes>(
                msgRes => { /* use your response message here */ }));
        }

        // responder in-host or in-net that have to respond always for messages
        private static IResponder<MyMessageReq, MyMessageRes> responder3 =
            new Responder<MyMessageReq, MyMessageRes>(
                netTcpRequesterAddress: "net.tcp://127.0.0.1:27273/Demo"
            ) { ResponseFunc = RespondMessage };

        // method that receive messages and need to create respond message
        private static MyMessageRes RespondMessage(MyMessageReq message)
        {
            return new MyMessageRes { Data = "CodingByToDesign.NET" };
        }

        // requester in-host or in-net that can get responses
        private static IRequester<MyMessageReq, MyMessageRes> requester3 =
            new Requester<MyMessageReq, MyMessageRes>(
                netTcpRequesterAddress: "net.tcp://127.0.0.1:27273/Demo"
            ) { ResponseAction = ReceiveMessageBack3 };

        private static void ReceiveMessageBack3(MyMessageRes message)
        {
            // do what you want with received response messages here
        }

        // in-host or in-net send/request method 3
        private static void SendMessageAsync3()
        {
            // sending example message
            requester3.RequestSync(new MyMessageReq
            {
                Uri = new Uri("http://codingbytodesign.net"),
                TimeStampUtc = DateTime.UtcNow,
                HttpMethod = "GET"
            },
            // optional parameter if it is null ReceiveMessageBack3 will be used
            new Action<MyMessageRes>(
                msgRes => { /* use your response message here */ }));
        }
    }
}

At the end of this blog entry you can find solutions for download SimpleServiceBus Binary Assembly (1911 downloads) and SimpleServiceBus Source Code (1799 downloads). There is one more thing, I tested this solution on both .NET 4.5 for Windows and Mono for Mac OSX and both work great. If you have a chance to test it on Mono for GNU/Linux please let me know. SimpleServiceBus depends only on pure .NET 4.5 or Mono. It is one more thing, when you decide to use SimpleServiceBus you can very easily separate any sub-component and test it by emulate real environment around, this gives easy way to both non-functional and functional separation of system and/or product to easy deal with testing it. Enjoy!

p ;).

4 Replies to “SimpleServiceBus”

  1. I recompiled binary assembly for Any CPU platform. Sorry if you tried use this assembly on x64 platform. Now, should be fine, file for download is updated and optimized for speed.

  2. Pingback: Happy Holidays at The End of 2014 @ coding by to design

  3. Pingback: The Best of all for Software Architects @ coding by to design

  4. Pingback: Simple Service Bus Training @ coding by to design

Leave a Reply

Your email address will not be published. Required fields are marked *

*