This post is part of a series:
- Conquering NServiceBus part 1 – Getting Started
- Conquering NServiceBus part 2 – Initial configuration
- Conquering NServiceBus part 3 – A simple Saga
- Conquering NServiceBus part 4 – Testing
- Conquering NServiceBus part 5 – Troubleshooting DTC
Obviously before starting with sagas and the more advanced things NSB has to offer I need to create some sort of simple way of sending and receiving messages. I’ll start with the receiving end because that is the easiest one. There are some things needed here. I plan on using the NServiceBus.Host.exe for simplicity and before we initialize the bus we need a couple of queues for the messages (SQLite can be used as well). Since I am just testing things out I won’t be very thorough with the config file. A really simple config for the receiving endpoint could look like:
<configSections>
<section name="MsmqTransportConfig"
type="NServiceBus.Config.MsmqTransportConfig, NServiceBus.Core" />
<section name="UnicastBusConfig"
type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
</configSections>
<MsmqTransportConfig
InputQueue="ReceivingEndpointQueue"
ErrorQueue="Error"
NumberOfWorkerThreads="1"
MaxRetries="5" />
<UnicastBusConfig>
<MessageEndpointMappings>
<!-- This is the receiving endpoint and it does not need any mappings yet -->
</MessageEndpointMappings>
</UnicastBusConfig>
This is where I had some minor problems understanding things so I’ll go through them briefly. In the sample projects that come with NServiceBus it is named things like “SomeInputQueue” and if you haven’t had the NSB or SOA course with Udi it’s maybe not that easy to follow (or maybe it was just me). The queue that is specified in the MsmqTransportConfig is the queue this endpoint is assigned so any messages sent to a MessageHandler in this project will be sent to this message queue. Then of course the next step is to connect the sender to this queue somehow and in the config file this is done like follows:
<configSections>
<section name="MsmqTransportConfig"
type="NServiceBus.Config.MsmqTransportConfig, NServiceBus.Core" />
<section name="UnicastBusConfig"
type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
</configSections>
<MsmqTransportConfig
InputQueue="SendingEndpointQueue"
ErrorQueue="Error"
NumberOfWorkerThreads="1"
MaxRetries="5" />
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="MyProject.Messages"
Endpoint="ReceivingEndpointQueue" />
</MessageEndpointMappings>
</UnicastBusConfig>
I hope it makes more sense now so on to the MessageEndpointMappings. There are a few ways to configure this. You can for instance configure a whole assembly like above. NServiceBus will search for all assemblies that contains ”MyProject.Messages” in the assembly name so there is not really any need to be more specific than that. If you on the other hand like in the saga scenario want to configure just one specific message to an endpoint you can do that easily with a fully (assembly) qualified name.
<add Messages="NServiceBus.Saga.TimeoutMessage, NServiceBus"
Endpoint="TimeoutManager"/>
Next up is the initialization of the endpoint and there is a lot going on here. First of all I want full control over what is going on. Not because I don’t trust the developers on the NSB project but like Jeremy stated : “Don’t copy code you don’t understand”. I am not copying code here but I refuse to use code without fully understanding what it does if I am to use it in production eventually and this means dissecting NServiceBus and learning the darn thing! It all comes down to something extremely simple really. I can shorten everything to the following:
public class ReceivingEndpointConfig :
IConfigureThisEndpoint,
AsA_Server { }
When the host starts it will look for any class that implements the interface IConfigureThisEndpoint and AsA_Server tells the host that it should use MsmqTransport transactionally, XmlSerialization, load all message handlers and it will NOT “purge” (clear) the queues at startup and I might be forgetting something important. Yes!! NServiceBus ships with a bunch of IoC containers. The default one is the spring container so this will be used for inversion of control. I don’t care much about Spring so I’ll switch this to StructureMap later. With the simple code above I can create an equally simple handler like below.
public class MyMessageHandler : IMessageHandler<OneMessage>
{
public void Handle(OneMessage message)
{
//Do something with arrived message
}
}
As soon as a message of type OneMessage is sent to the queue ReceivingEndpointQueue the message will end up in the above method all your message class needs to do is implement IMessage.
public class OneMessage : IMessage
{
public string Title { get; set; }
}
That’s the receiving end. What about the sender? For this silly tutorial I will be using the web. In my website I am (for now) happy with a global static IBus that can send necessary OneMessage messages when needed. When the application starts up I make sure to start up a bus and then store it in Global.asax.
public static IBus Bus { get; private set; }
protected void Application_Start(object sender, EventArgs e)
{
Bus = Configure.WithWeb()
.Log4Net()
.SpringBuilder()
.XmlSerializer()
.MsmqTransport()
.IsTransactional(true)
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start();
}
A few new things here, earlier I discussed how AsA_Server did most of this configuration for us. Right now I am not using a server, nor a publisher. What I want in the web application is a bus to send messages to other endpoints. Later on we will probably have some sort of response (error code) back to the web server. It is extremely important to send error codes between the endpoints. When a message has been received and as soon as possible a simple integer should be returned. This is sometimes the only way to confirm that the message was actually received and it is a dead easy way of setting up your tests (more about testing in a later). Something more is new and that’s the Log4Net. Let’s add that to the configuration. Since most people seem to be using log4net I leave that config out. We all have different preferences but your app.config or web.config should look a bit like:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<log4net configSource="log4net.config" />
The previous entries are still needed so don’t remove it! Now I should have a pretty much working example at least on my machine.
Now I can send messages from the web to my pages.
Global.Bus.Send(new OneMessage { Title = "This is a title" });