This is part of the NServiceBus Upgrade Guide from Version 5 to 6, which also includes the following individual upgrade guides for specific components:
Feature Details
- Assembly Scanning Changes in NServiceBus Version 6
- No Async Suffix
- Dependency Injection Changes in NServiceBus Version 6
- Deprecated TransportMessage in NServiceBus Version 6
- Endpoint API changes in NServiceBus Version 6
- Extension Seam Changes in NServiceBus Version 6
- Migrate handlers and sagas to Version 6
- Header API changes in NServiceBus Version 6
- Messaging Changes in NServiceBus Version 6
- Moving away from IBus in Version 6
- Recoverability Changes in Version 6
- Serialization Changes in NServiceBus Version 6
- Subscription Changes in NServiceBus Version 6
- Transaction Configuration Changes in NServiceBus Version 6
Transports
- Azure Service Bus Transport (Legacy) Upgrade Version 6 to 7
- RabbitMQ Transport Upgrade Version 3 to 4
- SQL Server Transport Upgrade Version 2 to 3
- SQL Server Transport Upgrade - Supporting Unicode in Headers
Persistence
- Upgrade from NServiceBus Azure Version 6
- NHibernate Persistence Upgrade Version 6 to 7
- NHibernate Persistence - Resolving incorrect timeout table indexes
- RavenDB Persistence Upgrade from 3 to 4
Hosting
Other
- Moving to the DataBus AzureBlobStorage Package
- Azure Cloud Services Host Upgrade Version 6 to 7
- NServiceBus.Azure package deprecated
- Gateway Upgrade Version 1 to 2
- NServiceBus Testing Upgrade Version 5 to 6
- Callback Changes in NServiceBus Version 6
- Migrating the distributor to use sender-side distribution
- Tool and Helper Changes in NServiceBus Version 6
Upgrading a major dependency like NServiceBus requires careful planning, see the general recommendations article to learn more about the optimal upgrade process.
Move to .NET 4.5.2
The minimum .NET version for NServiceBus version 6 is .NET 4.5.2.
All projects (that reference NServiceBus) must be updated to .NET 4.5.2 before updating to NServiceBus version 6.
It is recommended to update to .NET 4.5.2 and perform a full migration to production before updating to NServiceBus version 6. This will help isolate any issues that may occur.
For solutions with many projects, the Target Framework Migrator Visual Studio extension can reduce the manual effort required in performing an upgrade.
See also:
While a minimum of .NET 4.5.2 is required, it is recommended to update to at least .NET 4.6.1 since this gives access to Task.CompletedTask.
Update NServiceBus dependencies
All NServiceBus dependencies for an endpoint project are managed via NuGet. Open the Manage NuGet Packages window for the endpoint project, switch to the Updates tab and look for packages that start with NServiceBus. Update each one to the latest package.
Once packages have been updated the project will contain quite a few errors. This is expected as a lot of things have changed.
See also:
- NuGet Package Manager Dialog - Updating a Package
- NuGet Package Manager Console - Updating a Package
Update endpoint configuration
In previous versions of NServiceBus, connecting a process to the transport required an instance of IBus
. Starting from version 6, this concept has been deprecated and instead, an instance of IEndpointInstance
is required. The code required to create and configure an IEndpointInstance
is very similar to the code found in version 5 endpoints for creating and configuring IBus
instances.
This section describes updating a self-hosted endpoint. For endpoints that rely on the NServiceBus Host, see: NServiceBus Host Upgrade Version 6 to 7.
First, change all mentions of BusConfiguration
to EndpointConfiguration
. Note that EndpointConfiguration
has a required constructor parameter to set the endpoint name. In NServiceBus version 5, the name of the endpoint was provided via the .
method on the BusConfiguration
class. This call is no longer required in version 6 and the method is deprecated.
Most of the other method calls on EndpointConfiguration
work the same way as they did on BusConfiguration
. The methods that have changed between versions will each have deprecation messages that describe how to achieve the same effect in version 6.
Once the instance of EndpointConfiguration
has been created, it can be used to create an IEndpointInstance
. In versions 5 and below, this step is accomplished using the Bus
static class. In version 6, this has been replaced with an Endpoint
static class that works in a similar manner.
In NServiceBus version 6 and above, any operation that interacts with the transport is asynchronous and returns a Task
. This includes the Start
method on the static Endpoint
class and the Stop
method on IEndpointInstance
. Ideally these methods are called from within an async
method and the results can simply be awaited
.
async Task Run(EndpointConfiguration endpointConfiguration)
{
// pre startup
var endpointInstance = await Endpoint.Start(endpointConfiguration);
// post startup
// block process
// pre shutdown
await endpointInstance.Stop();
// post shutdown
}
If this is not the case then these calls must be converted back into synchronous ones using GetAwaiter().
. It is recommended that this conversion occur early in the application lifecycle.
void Run(EndpointConfiguration endpointConfiguration)
{
RunAsync(endpointConfiguration).GetAwaiter().GetResult();
}
async Task RunAsync(EndpointConfiguration endpointConfiguration)
{
// pre startup
var endpointInstance = await Endpoint.Start(endpointConfiguration);
// post startup
// block process
// pre shutdown
await endpointInstance.Stop();
// post shutdown
}
Note that in NServiceBus version 5, IBus
implements IDisposable
and stops communicating with the transport when Dispose
is called. It is common to call Bus.
from within a using
block in console applications. In version 6, stopping an instance of an endpoint is asynchronous and must return a Task
which is not possible with the signature of IDisposable
. IEndpointInstance
does not implement IDisposable
and explicitly calling Stop
and await
ing the returned Task
is the only way to shut down the endpoint.
See also:
- Migrating from IBus provides more in-depth discussion about the decision to deprecate
IBus
and how to handle other scenarios that depend onIBus
. - Endpoint API Changes in NServiceBus Version 6
- NServiceBus Host Upgrade Version 6 to 7
- Transaction Configuration Changes in NServiceBus Version 6
- Recoverability Changes in NServiceBus Version 6
- Assembly Scanning Changes in NServiceBus Version 6
Update handlers
In NServiceBus version 6, the signature of IHandleMessages
has been changed to support asynchronous processing. In versions 5 and below, each message is handled by a dedicated thread, so NServiceBus is able to take advantage of thread static state to keep track of the message being handled as well as the current transaction. In version 6, each message is handled by a task which may run on several threads before processing is completed. Rather than rely on thread context and state, each handler is explicitly passed in a context object with all of the information it needs to execute.
This context includes methods to send and publish new messages. As NServiceBus can no longer rely on thread static state to access information about the message and transaction being handled, it is not possible to rely on an injected copy of IBus
to perform these operations. It is necessary to always send and publish new messages using the context object rather than an injected instance of the endpoint.
As each handler is running in the context of a transport receive operation (an I/O context) and is likely to contain other asynchronous operations (such as sends and publishes), all handlers must return a Task.
To update a handler to NServiceBus version 6 follow this process:
- As the signature of
IHandleMessages
has changed, Visual Studio will show an error that the handler is not implementing the interface. To correctly implement the handler interface, change the return type of the<T> Handle
method fromvoid
toasync Task
. Next add a second parameter to theHandle
methodIMessageHandlerContext context
. - If the handler has an instance of
IBus
injected into it, it must be removed. Prior to removing it, rename it tocontext
as all operations that previously relied onIBus
will now go through the passed in instance ofIMessageHandlerContext
. - Finally, the methods on
IMessageHandlerContext
all return tasks. It is important toawait
each of these tasks.
See also:
- Migrate Handlers and Sagas to NServiceBus Version 6
- Migrating from IBus
- Messaging Changes in NServiceBus Version 6
Update sagas
Updating a saga is similar to updating a handler with a few extra steps.
The Saga
base class has been moved from the NServiceBus.
namespace to the NServiceBus
namespace. Remove all using
statements that refer to NServiceBus.
(or change them to refer to NServiceBus
if this using statement doesn't already exist in the class).
Update all of the IHandleMessages
implementations using the process outlined in the previous section. Note that IAmStartedByMessages
implementations can be updated in the same manner.
Check the implementation of ConfigureHowToFindSaga()
. NServiceBus will be able to automatically correlate any message that is a reply to a message originally sent by this saga. For any other message type, including messages that can start the saga, an explicit mapping is required.
Remove the [Unique]
attribute from the saga data class. NServiceBus automatically makes correlated saga properties unique in version 6.
Note that calls to RequestTimeout()
now require an instance of IMessageHandlerContext
to be passed in. Pass in the context parameter that was passed in to the Handle()
method. Additionally, this method returns a Task
which should wait for the response with await
.
See also:
- Migrate Handlers and Sagas to NServiceBus Version 6
- Migrating from IBus
- Messaging Changes in NServiceBus Version 6
Sending and publishing outside of a handler
Once all handlers and sagas in an endpoint have been updated to NServiceBus version 6, there may still be places in the code that send and publish messages using an instance of IBus
that need to be updated.
All message handlers and sagas that are included in the endpoint should be updated before taking this step. It is important that the techniques presented here are not used from inside message handlers or transactional consistency with the transport is not guaranteed.
The endpoint instance returned from Endpoint.
or Endpoint.
implements IMessageSession
which contains Send()
and Publish()
methods that can be used outside of a message handler or saga. If the endpoint sends messages in the same part of the code that creates/starts the endpoint, call these methods on the returned endpoint instance directly.
As the Send
and Publish
methods on the endpoint instance should not be used from within a handler or saga, there is no implementation of the interface injected into dependency injection. For recommendations on how to get access to IMessageSession
in other locations, see Dependency Injection.
See also: