Moving away from IBus in Version 6

Component: NServiceBus

Starting with Version 6, the IBus interface has been deprecated.

The IBus interface was one of the key interfaces when using previous versions. It provided access to many of the operations like sending messages, subscribing to events, and manipulating headers. The IBus interface was available through dependency injection in message handlers, any custom components that were registered in the container and through other mechanisms like the saga base class.

Reasons for deprecating IBus

The IBus interface contained numerous methods and properties. However, not all of them are valid in all scenarios where an instance of IBus was exposed and this can lead to confusion. For example, the methods Reply and ForwardCurrentMessageTo are always available on the IBus interface, but they are only relevant in the context of handling an incoming message. Using them in other scenarios will throw an exception.

For users new to the API, the fact that IBus was available in message handlers using Dependency Injection wasn't obvious, especially when trying to send or publish messages from inside message handlers. Rather than using dependency injection, an IMessageHandlerContext parameter is now available in all the message handlers. This parameter exposes all of the appropriate actions to the message handler. Methods that aren't applicable will not be available making the API simpler.

All of the previous Bus methods now available via the IMessageHandlerContext parameter in the message handlers and the methods in the IMessageSession interface available when the endpoint is started are fully async. However, the original method names are retained rather than adding the async suffix to make the upgrade easier.

Migrating away from IBus

Some scenarios involving IBus include: endpoint creation, sending messages during endpoint startup, sending messages from within message handlers, using the injected IBus in custom components also registered in the container.

During Endpoint Creation

In previous versions to start a new instance of an endpoint, either the Bus static class or the IStartableBus interface was used. In Version 6 these two concepts have been replaced. More information can be found in the hosting section of the documentation. Instead of the Bus class, a new class called Endpoint helps to start the endpoint.

BusConfiguration has been deprecated. Use EndpointConfiguration instead to configure and start the endpoint. Because IBus has been deprecated, the BusConfiguration class has been renamed to EndpointConfiguration to keep terminology consistent.

6.x NServiceBus
Edit
var endpointConfiguration = new EndpointConfiguration("EndpointName");

// Custom code before start
var endpointInstance = await Endpoint.Start(endpointConfiguration)
    .ConfigureAwait(false);
// Custom code after start

// Block the process

// Custom code before stop
await endpointInstance.Stop()
    .ConfigureAwait(false);
// Custom code after stop
5.x NServiceBus
Edit
var busConfiguration = new BusConfiguration();

// Custom code before start
var startableBus = Bus.Create(busConfiguration);
using (var bus = startableBus.Start())
{
    // Custom code after start

    // Block the process

    // Custom code before stop
}
// Custom code after stop

Starting the endpoint provides access to IEndpointInstance which can be used to send messages during endpoint start up instead of using the IBus interface.

"Send-only" endpoints were created by calling the CreateSendOnly method on the Bus class in previous versions. In version 6 there is no longer a separate method to create or start "Send-Only" endpoints. Configure the endpoint to be "Send-Only" with the SendOnly method on EndpointConfiguration and create/start it with the Endpoint class.

Accessing the CurrentMessageContext

Previously it was possible to access message parameters, such as MessageId, ReplyToAddress and the message headers, via the CurrentMessageContext property on the IBus interface. These message properties are now available directly via the message handler context parameter.

6.x NServiceBus
Edit
public async Task Handle(MyMessage message, IMessageHandlerContext context)
{
    var messageId = context.MessageId;
    var replyToAddress = context.ReplyToAddress;
    var headers = context.MessageHeaders;
}

Sending messages inside message handlers

Instances of IBus that were being injected into message handler classes by the IoC container can be safely deleted.

The message handler signature now includes an additional IMessageHandlerContext parameter, which provides the methods that used to be called from IBus. Use the IMessageHandlerContext to send and publish messages from within the message handler.

6.x NServiceBus
Edit
public class SendAndPublishHandler :
    IHandleMessages<MyMessage>
{
    public async Task Handle(MyMessage message, IMessageHandlerContext context)
    {
        await context.Send(new MyOtherMessage())
            .ConfigureAwait(false);
        await context.Publish(new MyEvent())
            .ConfigureAwait(false);
    }
}

Sending messages outside message handlers

A common use of IBus is to invoke bus operations outside of the pipeline (e.g. in handlers, sagas and pipeline extensions), such as sending a message from an ASP.NET request or from a client application. Instead of an IBus the IMessageSession offers all available messaging operations outside the message processing pipeline. For example:

6.x NServiceBus
Edit
var endpointInstance = await Endpoint.Start(endpointConfiguration)
    .ConfigureAwait(false);
IMessageSession messageSession = endpointInstance;
await messageSession.Send(new SomeMessage())
    .ConfigureAwait(false);

In this example a message is being sent during startup of an Endpoint. Hence the IMessageSession is available via the IEndpointInstance class from Endpoint.Start. Note that implicitly converting from IEndpointInstance to IMessageSession is optional but it is preferred as IMessageSession offers a more concise API for messaging interactions.

For other scenarios (i.e. not at startup) that need access to IMessageSession there are two ways to achieve this:

  1. Static property. In this scenario, during startup, the IMessageSession instance is assigned to a static property that is accessible from other components.
  2. Injecting via container. See "Dependency Injection" below.

If the endpoint is hosted using NServiceBus.Host, use the IWantToRunWhenEndpointStartsAndStops interface.

Dependency Injection

In previous versions the IBus interface was automatically registered in the IOC container. In Version 6, the new context-aware interfaces, for example, IEndpointInstance, IMessageSession and IMessageHandlerContext, etc., will not be automatically registered in the Container.

In Versions 5 and below, when a custom component was registered in the container, the custom component had access to the IBus instance via dependency injection.

When upgrading such custom components to Version 6, it is not safe to simply replace all instances of IBus with IMessageSession. It depends on the usage of the IBus inside the custom component.

Scenario 1: If the custom component was sending messages using the injected IBus from outside of message handlers, for example, in an MVC Controller class, then it is safe to register the IMessageSession when self hosting. This interface can then be used to send messages. See Sending from an ASP.NET MVC Controller for an example of this.

Scenario 2: If the custom component is accessed from within message handlers then the IMessageHandlerContext parameter should be passed to the custom component instead of the IMessageSession interface to either send or publish messages.

Some of the dangers when using an IMessageSession interface inside a message handler to send or publish messages are:

  • Those messages will not participate in the same transaction scope as that of the message handler. This could result in messages dispatched or events published via the IEndpointInstance interface even if the message handler resulted in an exception and the operation was rolled back.
  • Those messages will not be part of the batching operation.
  • Those messages will not contain any important message header information that is available via the IHandlerMessageContext interface parameter, e.g., CorrelationId.

UnicastBus made internal

Accessing the builder

When using the IBuilder interface outside the infrastructure of NServiceBus it was possible to use a hack by casting the IBus interface to UnicastBus and then accessing the Builder property like this:

5.x NServiceBus
Edit
var builder = ((UnicastBus) bus).Builder;

This is no longer supported. Instead of using IBuilder directly, it is advised to use dependency injection via the container of choice.

Setting the host information

Control over HostInformation was previously done using UnicastBus.HostInformation. This is now done using a more explicit API to set the host identifier using the endpoint configuration.

6.x NServiceBus
Edit
endpointConfiguration.UniquelyIdentifyRunningInstance()
    .UsingNames("endpointName", Environment.MachineName);
// or
var hostId = CreateMyUniqueIdThatIsTheSameAcrossRestarts();
endpointConfiguration.UniquelyIdentifyRunningInstance()
    .UsingCustomIdentifier(hostId);

Accessing ReadOnlySettings

Accessing ReadOnlySettings using UnicastBus.Settings is no longer supported as these settings should only be accessed inside features, the pipeline and the start/stop infrastructure.


Last modified