Sunday, April 20, 2008 8:33 PM
Enterprise Service Bus Messaging Using nServiceBus
I have been working lately with a big group of fellow developers here in SilverKey on the architecture and design of a relatively big project that required much services and messaging work. We thought that we should implement our public services the REST way using WCF for .NET 3.5, with so many customizations, and that we'll use a library called nServiceBus for internal messaging. Mohammed Nour wrote a little about thinking in REST.
nServiceBus is a framework for handling publisher/subscriber (pub/sub) model of messaging. It provides reliable messaging via the Enterprise Service Bus (ESB) pattern, and uses MSMQ as the physical bus.
It's an interesting piece of work to look at actually; of course free, open source. I have been involved in evaluating it for our project, and wrote a document about it as part of my work, so that it's easier for the rest of the team to use it later. As the documentation for nServiceBus is very limited at this stage of the project, I and my boss Dody decided to share the document with the community.
Another very important reason for this is enabling the nServiceBus group to correct and enhance the document as much as possible. That's why the document is published under the Creative Commons Attribution-Share Alike 3.0 Unported License.
Download the document
WARNING: This IS going to change, see the nServiceBus Yahoo group for updates to this document.
If you are lazy to download check this out:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Author: Mohammad Meligy
Revision Number: 1.1
Status: Public Draft
Revision History 2
Non Goals 5
Major Features 5
How it works 6
Defining the message contracts 6
Writing the code to handle the messages 6
Setting up messaging communication 7
Logging (Optional) 12
Security Consideration 12
Security Constraints 12
This document shows the use of nServiceBus library (www.nservicebus.com) for managing enterprise messaging using the service bus pattern. The model explained is an advancement of a publisher / subscriber model.
The document is written to be guidance for developers involved in intercommunication between components in enterprise project, however, it is written with no specific relevance to the project components, and can be used for any project that implements this kind of messaging.
There're some common terms used in this document:
A message is the object that groups the data you want to pass from a module to another module or system for processing outside your module.
This is the code that creates the message and puts it publicly to be available for later processing.
Note: It's very common when dealing with nServiceBus to call the publisher as a "Client"
This is the code that checks for published messages and passes is responsible for performing any desired operations on them.
Note that the subscriber that subscribes to a certain request message for example may want to send a response message in return, hence, it then acts as a publisher, and so. It's normal that the module that acts as a publisher acts also as a subscriber and vice-versa.
Note: It's very common when dealing with nServiceBus to call the subscriber as a "Server"
This is the shared message store where all the messages are be written to by the publishers requesting processing, and then later read by the subscribers for processing. Once the messages are delivered to subscribers, they're typically removed from the message store.
- Enable asynchronous messaging across multiple servers.
- Ensure reliability for the asynchronous messaging.
- Enable a publisher / subscriber model for the messaging.
- Enable multiple subscribers to each published message.
- Enable a publisher to receive response messages from subscribers.
- Enable canceling of already published messages.
- Specify the sequence of message subscribers handling via configuration (still available from inside the subscriber code).
- Setting a server to act as service bus for multiple publishers/subscribers.
- Setting the publishers to send messaging to a service bus asynchronously.
- Setting multiple subscribers inside a service bus.
- Limiting the handling of messages based on their type.
- MSMQ – Acts as store for published messages
- Spring.NET Library (On all the publisher and subscriber application – included with nServiceBus assemblies) – For initializing the messaging infrastructure
- Log4net Library (http://logging.apache.org/log4net) - For logging purposes
- Serialization (On all the code classes that are included in published / returned messages)
How it works
You create the message type, create a type that holds the processing of the message (called message handler), configure the publisher and create the message instance itself that it publishes to the bus, and, configure the subscriber to subscribe to the bus and map the message instance to new message handler instance.
You'll notice that the difference between the client and the server is really small. A client publishes a message to one or more primary buses. The server subscribes to the messages it has handlers for that come on the primary bus. But, for the server to be able to send back "response" messages to the client, the client also has its own bus (queue) that it subscribes to for handling response messages.
Defining the message contracts
You define the message type (class) normally in any VS project with certain considerations:
It should implements an interface "NServiceBus.IMessage".
This interface does not require you to implement any methods / properties.
- It should be attributed as "Serializable".
- It's highly recommended that your message have an identity field of type GUID.
This message acts as data contract between the publisher and subscriber, and it should be available to both. This is the actual data that's being passed between them.
Writing the code to handle the messages
A handler is the business logic that does the actual processing of a message. When the subscriber receives a message, it checks which handler(s) it should call to process this message. A handler is independent from the subscriber and can be used with multiple subscribers though.
When creating the handler type (class), you should either
- implement the interface "NServiceBus.IMessageHandler<MESSAGE_TYPE>"
- Inherit from class "NServiceBus.BaseMessageHandler<MESSAGE_TYPE>"
MESSAGE_TYPE is the type of the message to handle.
The two options are equal in effect. You write a method "public void Handle(MESSAGE_TYPE)" where you write the code that actually processes the message.
Note: You can implement the interface multiple times for MESSAGE_TYPE_1, MESSAGE_TYPE_2, etc, and then you have to implement the methods "public void Handle(MESSAGE_TYPE_1)" and "public void Handle(MESSAGE_TYPE_2)", etc.
In this example, the handler just creates a message of a different type (which it does not have to do or have to define) and sends it to the service buss.
The last line has the method "Reply" which accepts "paramas" of message(s) that act as response to the original message and sends the response message(s) back to the queue of the client (who sent the original request message).
To indicate that there was an error processing the message. NServiceBus promotes error codes and creating custom messages that represent the error against throwing an exception.
Here's a sample code or creating "enum" for wrapping error codes and returning it:
Setting up messaging communication
Now, you have a message type, and a message handler. What's remaining is writing the publisher that sends this message to the service bus, and the subscriber that asks the service bus to subscribe to any message of the type(s) you want, and before all that, creating the service bus itself.
Preparing the service bus
The first thing you need to do is to create the MSMQ queue that acts as a service bus. The name of the queue will later be available to publishers and subscribers to write messages to / read messages from.
Creating the publisher
The publisher is the code that sends the messages to the service bus through configurations. Before writing anything, you need to add references to the following assemblies:
The way nServiceBus highly promotes is setting the publisher configuration in the app.config/web.config of the Visual Studio project that contains publishing code using Spring.Net configuration.
A typical configuration looks like this:
A configuration section that registers the Spring.Net configurations
The "Common" and "log4net" parts are optional and are only used in case you want to use logging.
- Create the standard sections for Spring.NET
Replace the part "<!-- All the required configuration for nServiceBus comes here -->" with the actual configuration to use. A typical configuration looks like:
The properties that matter in this context are:
Sets the path to the queue where the messages will be read from. This is essential as the publisher might also subscribe to messages (typically responses to published requests).
Note: For MSMQ v3 (Windows XP, 2003), this must be a local queue.
This connects the message - based on the message type (class, the one that implements "IMessage" interface) – to the MSMQ address where it will be published.
As shown above, this is written as a dictionary, where:
- "key": is either the name of the message type (class) – or – the name of an assembly, so that nServiceBus looks inside this assembly and locate all the classes that implement the "IMessage" interface.
- "value": is name of the MSMQ queue to publish the "key" messages to
Write the actual code that sends the message to the service bus
In this sample, "RequestDataMessage" is just the message type (class).
The code is pretty simple, you:
- Use Spring.NET to create the service buss
- Create the message itself normally and fill its members
- Send the message to be published to the bus (This has some alternatives discussed later)
As the message is published asynchronously, you can optionally create a callback method that handles the message. A code for something like that would look like:
You send the message and sending returns an "ICallback" object. This object has single method "Register" which you use to register "AsyncCallback" delegate to a method that will be called asynchronously when the sever returns a reply, which is "RequestDataComplete" in our example. A sample implementation of this method would look like:
Clearly, you can see that result returned is a "NServiceBus.CompletionResult" which has both "state" which has the original sent message, and "messages" which has the response messages.
Creating the subscriber
The subscriber is the code that reads the messages published to the service bus, and pass the messages to the messages handler(s) set for it.
The configuration for the subscriber is very similar to the publisher:
- Steps 1 to 3 in the publisher are the same for the subscriber
The final nServiceBus specific configurations would look like:
Note the following sections as well:
This is the MSMQ queue where the subscription messages will be stored (The mapping between the subscriber and publishers)
Note: For MSMQ v3 (Windows XP, 2003), this must be a local queue.
This is a list of assemblies to look in for message handler types (classes, ones that implement "NServiceBus.IMessageHandler<MESSAGE_TYPE>"), so that it maps the handlers to the messages it receives
Writing the actual code that subscribes to the bus. This is very simple piece of code
You can see it's very simple. You create the "Bus" object from the information in the config file using the "Spring" library, and just start the bus. It loads all the necessary information like which messages to subscribe to and the mapping between message types and message handlers, etc, from the config.
- Now you need to deploy the code that runs the server. Note that the bus should be living forever! You'll want to treat it as you treat a Windows Workflow Foundation Workflow Runtime for example. Either make it an independent Windows Service, or write it in some Application even of the global.asax of a web application.
For the error logging and such, nServiceBus library has dependency on another library called Log4net. You can use that for any kind of logging. Sample logging code looks like:
For Log4net library specific documentation check
Seeing how nServiceBus works, you notice you have typically two queues, one for the server and another for the client. You also notice that you have two operations for each, read and write.
To setup MSMQ, you can use public queues, but those are hard to create and are very insecure. Typically you use the default private queues. This causes few constraints on the queue operations.
- For reading from the queue (AKA subscribing to the bus), the queue has to be on the same machine as the subscriber. You cannot subscribe to a queue that is on a different machine if you are using MSMQ version 3 (like using Windows 2003).
- To write to the queue (AKA, publish to the bus), the OS process running client/publisher has to be running with a use account that has sufficient privileges on the machine that has the queue you want to write to. This means you'll typically be running the client and server on two machines in the same LAN with Active directory and sufficient user access, which is a common scenario anyway.
Where to find a copy of the examples in this document or get a working example for nServiceBus in general?
The code snippets in this document are mostly coming from the "FullDuplex" example that comes with the library source code.
The source code can be found at: http://sourceforge.net/projects/nservicebus
For more examples, check the library Yahoo group at: http://tech.groups.yahoo.com/group/nservicebus
When I downloaded the nServiceBus source from the library SVN repository I found the configuration much different than described in this document. Any Idea?
The next version of nServiceBus will have different configuration. It's not documented here because it's NOT a complete release yet so is still subject to change before the next release.
For differences between the configuration of the current release and the upcoming release, check nServiceBus wiki page at: http://nservicebus.wiki.sourceforge.net/Configuration
There's also incomplete documentation of the examples on nServiceBus wiki at http://nservicebus.wiki.sourceforge.net/Samples
Is there any documentation for nServiceBus?
There are few resources:
However, most of those are either very limited or incomplete.
How do I write the name of a MSMQ queue that exists on a different computer?
You write the name of the queue in a format like "QUEUE_NAME @MACHINE_NAME"
MACHINE_NAME is the computer name of the machine that has the queue.
QUEUE_NAME is the name of the queue itself
Filed under: WCF, SilverKey Tech, SOA, Architecture, ESB, nServiceBus