Thursday 24 May 2012

Collections in NServiceBus 2.6 messages

I needed to create an NServiceBus message type (an implementation of IMessage) that contained a collection of sub items. My initial thought was to expose the collection as an IEnumerable in order to preserve encapsulation - I didn’t want client code to be able to modify the collection. Here’s an example:

public class MyMessage : IMessage
{
    public int SomeCode { get; set; }

    public IEnumerable<ListItem> Items { get; set; }
}
public class ListItem
{
    public string Key { get; set; }
    
    public string Message { get; set; } 
}

The problem was that the collection was turning up empty at the destination.

This turns out to be a feature of the NServiceBus XML serializer. This is described as follows:

“NServiceBus has its own custom XML serializer which is capable of handling both classes and interfaces as well as dictionaries and does not use the WCF DataContractSerializer. Binary serialization is done using the standard .net binary serializer.” - http://nservicebus.com/Performance.aspx

However, it seems the XML serializer isn’t as fully featured as other XML serializers but it is focussed on addressing problems relating to moving messages around quickly and efficiently.

In this case the solution was to change from using IEnumerable<T> to List<T>. Not too painful really.

public class MyMessage : IMessage
{
    public int SomeCode { get; set; }

    public List<ListItem> Items { get; set; }
}

Note that a number of serialization issues in NServiceBus – including this one - can be addressed by using the NServiceBus binary serializer.

NServiceBus built-in configurations and profiles

I’ve been using NServiceBus for quite a while now and am really happy with it. I’ve been making good use of the generic host (NServiceBus.Host.exe) to run services based on NServiceBus and really like the simplicity this provides. To get the most out of the generic host I’ve found you need an understanding of 2 aspects of NServiceBus:

  1. Built-in configurations (provided as interfaces your endpoint configuration classes can implement)
  2. Profiles (command line arguments supplied to the generic host)

What’s the difference? As I see it:

  1. Built-in configurations – Set up the nature of the endpoint in code (pretty much baked in). 
  2. Profiles – Can be changed at runtime (when invoking the generic host).

I keep having to look up what the out-of-the-box configurations and profiles are so I thought I’d create this post as an aide-mémoire.

Built-in configurations

The built-in configuration interfaces are described here: http://nservicebus.com/GenericHost.aspx

Firstly there are 3 configuration interfaces:

  1. AsA_Client
  2. AsA_Server
  3. AsA_Publisher

Each of these interfaces makes use of the XmlSerializer, the MsmqTransport, and the UnicastBus but configures them differently:

  • AsA_Client
    • Sets MsmqTransport to be non-transactional
    • Purges its queue of messages on start-up
    • Processes messages using its own permissions, not those of the message sender
  • AsA_Server
    • Sets the MsmqTransport to be transactional
    • Does not purge messages from its queue on startup (making it fault-tolerant)
    • It processes messages under the permissions of the message sender (called impersonation) which prevents elevation of privilege attacks
  • AsA_Publisher
    • Extends AsA_Server
    • Indicates to the infrastructure that a storage for subscription requests is to be set up (see the NServiceBus profiles page).

I have to say I don’t like the naming conventions here. When I first saw them I assumed a server would send messages and a client receive them. That’s not the case at all. The way I think of things is that a client is a fairly transient endpoint; it doesn’t matter if it looses messages that have been sent to it if it’s restarted. Servers and publishers are endpoints that need to be more fault tolerant (e.g. a message endpoint in front of a business process).

Profiles

NServiceBus generic host profiles are described here: http://nservicebus.com/Profiles.aspx 

And here: http://nservicebus.com/MoreOnProfiles.aspx

Firstly, there are 2 categories of profile:

  • Environment Profiles
    • Help avoid the error prone manual configuration (e.g. when moving from Development to Production via Integration)
    • Enables easy transition of the system without any code changes
  • Feature Profiles
    • Turn on an off NServiceBus features (e.g. turning on and off the Distributor, Gateway and timeout manager)

The 3 environmental profiles are:

  • Lite
    • The default profile
    • Used if no explicit profile is defined
    • Configures all the persistence like sagas, subscriptions, timeouts etc to be InMemory
    • Turns the TimeoutManager and Gateway on by default
    • Installers are always invoked (installers were introduced in NServiceBus 3.0)
    • Logging is done to the console
  • Integration
    • Suitable for running your endpoint in integration and QA environments
    • Storage is persistent using queues or RavenDB
    • Features like TimeoutManager and Gateway are now turned off by default
    • Installers are invoked to make deployment easier to automate
    • Logging is done to the console
  • Production
    • Sets your endpoint up for production use
    • All storage is durable and suitable for scale out
    • Installers are not invoked since your endpoint will probably be installed as a windows service and not running with elevated privileges
    • Installers are only run when you install the host
    • Logging is done to a logfile in the runtime directory since again you’re most likely running as a windows service

The feature related profiles are:

  • MultiSite
    • Turns the the gateway on
  • Time
    • Turns the timeout manger on
  • Master
    • Makes the endpoint a “master node endpoint” (it will run the Gateway for multisite interaction, Timeout manager and the Distributor)
    • It will also start a worker that will enlist with the Distributor
    • Can’t be combined with the Worker or Distributor profiles
  • Worker
    • Makes the current endpoint enlist as a worker with its distributor running on the master node
    • Can’t be combined with the Master or Distributor profiles
  • Distributor
    • Starts the endpoint as a distributor only
    • The endpoint won’t do any actual work and only distribute the load among its enlisted workers
    • Can’t be combined with the Master and Worker profiles
  • PerformanceCounters
    • Turns the NServiceBus specific performance counters on

Don’t forget that calling a profile is done as a command line argument to the generic service host and must be qualified with a namespace:

NServiceBus.Host.exe NServiceBus.Lite