Routing system extensibility points

Component: NServiceBus
NuGet Package NServiceBus (5.x)

Extending the NServiceBus routing subsystem with a custom data source makes sense in following scenarios:

  • When centralizing all routing information in a database.
  • When dynamically calculating routes based on endpoint discovery protocol (similar of UDDI).
  • When using a convention based on message naming.

MessageEndpointMappings

The routing system can be extended in a static manner (once at startup) by providing custom sources of routing information to enrich or replace the standard routing configuration (UnicastBusConfig/MessageEndpointMappings configuration section in app.config file).

It can be done either by using a configuration source:

public class ConfigurationSource :
    IConfigurationSource
{
    public T GetConfiguration<T>() where T : class, new()
    {
        if (typeof(T) == typeof(UnicastBusConfig))
        {
            // read from existing config
            var config = (UnicastBusConfig)ConfigurationManager
                .GetSection(typeof(UnicastBusConfig).Name);
            if (config == null)
            {
                // create new config if it doesn't exist
                config = new UnicastBusConfig
                {
                    MessageEndpointMappings = new MessageEndpointMappingCollection()
                };
            }
            // append mapping to config
            var endpointMapping = new MessageEndpointMapping
            {
                AssemblyName = "assembly",
                Endpoint = "queue@machinename"
            };
            config.MessageEndpointMappings.Add(endpointMapping);
            return config as T;
        }

        // Respect app.config for other sections not defined in this method
        return ConfigurationManager.GetSection(typeof(T).Name) as T;
    }
}
busConfiguration.CustomConfigurationSource(new ConfigurationSource());

or a configuration provider:

public class ProvideConfiguration :
    IProvideConfiguration<UnicastBusConfig>
{
    public UnicastBusConfig GetConfiguration()
    {
        // read from existing config
        var config = (UnicastBusConfig) ConfigurationManager
            .GetSection(typeof(UnicastBusConfig).Name);
        if (config == null)
        {
            // create new config if it doesn't exist
            config = new UnicastBusConfig
            {
                MessageEndpointMappings = new MessageEndpointMappingCollection()
            };
        }
        // append mapping to config
        var endpointMapping = new MessageEndpointMapping
        {
            AssemblyName = "assembly",
            Endpoint = "queue@machinename"
        };
        config.MessageEndpointMappings.Add(endpointMapping);
        return config;
    }
}

or in the app.config

<configuration>
  <configSections>
    <section name="UnicastBusConfig"
             type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core"/>
  </configSections>
  <UnicastBusConfig>
    <MessageEndpointMappings>
      <add Assembly="MyMessages"
           Endpoint="Sales" />

      <add Assembly="MyMessages"
           Namespace="PriorityMessages"
           Endpoint="Preferred" />

      <add Assembly="MyMessages"
           Type="MyMessages.SendOrder"
           Endpoint="Sending" />
    </MessageEndpointMappings>
  </UnicastBusConfig>
</configuration>

The MessageEndpointMappings collection can be populated based on any external source. It is read during the endpoint start-up, before any messages are sent.

The route table is not updated during run-time, even if the contents of the mappings collection change. In case the routing data changes frequently, consider implementing a mechanism that would restart the endpoint when the change is detected.
For backwards compatibility a Messages attribute can be used instead of Type and Namespace attributes.

Related Articles


Last modified