Upgrade Version 7 to 8

Component: NServiceBus
This page targets a pre-release version. Pre-releases are subject to change and samples are not guaranteed to be fully functional.
This is a working document; there is currently no timeline for the release of NServiceBus version 8.0.

This document focusses on changes that is affecting general endpoint configuration and message handlers.

Transport configuration

NServiceBus version 8 comes with a new transport configuration API. Instead of the generic-based UseTransport<TTransport> method, create an instance of the transport's configuration class and pass it to the the UseTransport method. For example, instead of:

var transport = endpointConfiguration.UseTransport<MyTransport>();

transport.Transactions(TransportTransactionMode.ReceiveOnly);
var routing = t.Routing();
routing.RouteToEndpoint(typeof(MyMessage), "DestinationEndpoint");

use:

var transport = new MyTransport{
    TransportTransactionMode = TransportTransactionMode.ReceiveOnly
};

var routing = endpointConfiguration.UseTransport(transport);
routing.RouteToEndpoint(typeof(MyMessage), "DestinationEndpoint");

See the transport upgrade guide for further details.

The existing API surface is supported for NServiceBus version 8 via a shim API to ease migration to the new version. However, it is recommended to switch to the new transport configuration API to prepare for future upgrades of NServiceBus.

Dependency injection

NServiceBus no longer provides adapters for external dependency injection containers. Instead, NServiceBus version 8 directly provides the ability to use any container that conforms to the Microsoft.Extensions.DependencyInjection container abstraction. Visit the dedicated dependency injection changes section of the upgrade guide for further information.

Support for external logging providers

Support for external logging providers is no longer provided by NServiceBus adapters for each logging framework. Instead, the NServiceBus.Extensions.Logging package provides the ability to use any logging provider that conforms to the Microsoft.Extensions.Logging abstraction.

The following provider packages will no longer be provided:

CancellationToken support

NServiceBus version 8 supports cooperative cancellation using CancellationToken parameters. Where appropriate, optional CancellationToken parameters have been added to public methods. This includes the abstract classes and interfaces required to implement a message transport or persistence library, and other extension points like IDataBus, FeatureStartupTask, and INeedToInstallSomething. Implementers can be updated by adding an optional CancellationToken parameter to the end of method signatures. The change also includes callbacks that customize the behavior of NServiceBus:

  • when a critical error is encountered
  • when a message is retried
  • when a message is moved to the error queue
  • when a message is processed

Shutdown behavior

In all versions of NServiceBus, endpoint.Stop() immediately stops receiving new messages but waits for a period of time for currently running message handlers to complete.

In NServiceBus version 7 and below, the MSMQ, Azure Service Bus, RabbitMQ, Azure Storage Queues, and SQL transports allow handlers up to 30 seconds to complete before forcing an endpoint shutdown. In NServiceBus version 8, all transports block shutdown until all handlers complete or the transport transaction times out.

The CancellationToken available on the IMessageHandlerContext in NServiceBus version 8 is triggered when the host forces shutdown. For example, by default, the .NET Generic Host signals the cancellation token after 5 seconds.

However, if handlers do not observe the cancellation token, they will be allowed to complete before the endpoints shuts down. This means that if, for example, a handler calls Task.Delay(TimeSpan.Infinite), the endpoint will never shut down.

Therefore, it is recommended that all message handlers observe the cancellation token to enable forced shutdown when required.

New gateway persistence API

The NServiceBus gateway has been moved to a separate NServiceBus.Gateway package and all gateway public APIs in NServiceBus are obsolete and will produce the following warning:

Gateway persistence has been moved to the NServiceBus.Gateway dedicated package. Will be treated as an error from version 8.0.0. Will be removed in version 9.0.0.

How to upgrade

Error notification events

In NServiceBus version 7.2, error notification events for MessageSentToErrorQueue, MessageHasFailedAnImmediateRetryAttempt, and MessageHasBeenSentToDelayedRetries using .NET events were deprecated in favor of Task-based callbacks. In NServiceBus version 8 and above, the event-based notifications will throw an error.

Error notifications can be set with the Task-based callbacks through the recoverability settings:

var recoverability = endpointConfiguration.Recoverability();

recoverability.Immediate(settings => settings.OnMessageBeingRetried((retry, ct) =>
{
    log.Info($"Message {retry.MessageId} will be retried immediately.");
    return Task.CompletedTask;
}));

recoverability.Delayed(settings => settings.OnMessageBeingRetried((retry, ct) =>
{
    log.Info($@"Message {retry.MessageId} will be retried after a delay.");
    return Task.CompletedTask;
}));

recoverability.Failed(settings => settings.OnMessageSentToErrorQueue((failed, ct) =>
{
    log.Fatal($@"Message {failed.MessageId} will be sent to the error queue.");
    return Task.CompletedTask;
}));

Disabling subscriptions

In previous versions, users sometimes disabled the MessageDrivenSubscriptions feature to remove the need for a subscription storage on endpoints that do not publish events, which could cause other unintended consequences.

While NServiceBus still supports message-driven subscriptions for transports that do not have native publish/subscribe capabilities, the MessageDrivenSubscriptions feature itself has been deprecated.

To disable publishing on an endpoint, the declarative API should be used instead:

var transportConfiguration = endpointConfiguration.UseTransport(new MyTransport());
transportConfiguration.DisablePublishing();

Change to license file locations

NServiceBus version 8 will no longer attempt to load the license file from the appSettings section of an app.config or web.config file, in order to create better alignment between .NET Framework 4.x and .NET Core.

In NServiceBus version 7 and below, the license path could be loaded from the NServiceBus/LicensePath app setting, or the license text itself could be loaded from the NServiceBus/License app setting.

Starting in NServiceBus version 8, one of the other methods of providing a license must be used.

Support for message forwarding

NServiceBus no longer natively supports forwarding a copy of every message processed by an endpoint. Instead, create a custom behavior to forward a copy of every processed message as described in message forwarding sample.

NServiceBus Host

The NServiceBus.Host package is deprecated. See the NServiceBus Host upgrade guide for details and alternatives.

NServiceBus Azure Host

The NServiceBus.Hosting.Azure and NServiceBus.Hosting.Azure.HostProcess are deprecated.See the NServiceBus Azure Host upgrade guide for details and alternatives.

Overriding the host machine name

RuntimeEnvironment.MachineNameAction is deprecated. The host machine name of an endpoint instance may be overridden using:

endpointConfiguration.UniquelyIdentifyRunningInstance()
    .UsingHostName("NewMachineName");`

DateTimeOffset instead of DateTime

Usage of DateTime can result in numerous issues caused by misalignment of time zone offsets, which can lead to time calculation errors. Although a DateTime.Kind property exists, it is often ignored during DateTime math and it is up to the user to ensure values are aligned in their offset. The DateTimeOffset type fixes this. It does not contain any time zone information, only an offset, which is sufficient to get the time calculations right.

> These uses for DateTimeOffset values are much more common than those for DateTime values. As a result, DateTimeOffset should be considered the default date and time type for application development."

In NServiceBus version 8, all APIs have been migrated from DateTime to DateTimeOffset.

NServiceBus Scheduler

In NServiceBus version 8, the Scheduler API has been deprecated in favor of options like sagas and production-grade schedulers such as Hangfire, Quartz, and FluentScheduler.

It is recommended to create a .NET Timer with the same interval as the scheduled task and use IMessageSession.SendLocal to send a message to process. Using message processing has the benefit of using recoverability and uses a transactional context. If these benefits are not needed then do not send a message at all and directly invoke logic from the timer.

The behavior in NServiceBus version 7 is to not retry the task on failures, so be sure to wrap the business logic in a try-catch statement to get the same behavior in NServiceBus version 8.

See the scheduling with .NET Timers sample for more details.

Meaningful exceptions when stopped

NServiceBus version 8 throws an InvalidOperationException when invoking message operations on IMessageSession when the endpoint instance is stopping or stopped to indicate that the instance can no longer be used.

Non-durable messaging

Support for non-durable messaging has been moved to the transports that can support it, which as of November 2020 is only the RabbitMQ transport. When using another transport, use of [Express] or message conventions to request non-durable delivery can safely be removed.

RabbitMQ user should use the new options.UseNonPersistentDeliveryMode() API provided by NServiceBus.RabbitMQ Version 7

Non-durable persistence

Support for non-durable persistence (previously known as InMemoryPersistence) has been removed from the NServiceBus package to a separate NServiceBus.Persistence.NonDurable package. To continue using it, add a reference to the new package and update the configuration code.

endpointConfiguration.UsePersistence<NonDurablePersistence>();

Timeout manager removed

With all currently-supported transports now supporting native delayed delivery, the timeout manager is no longer needed. Any calls to EndpointConfiguration.TimeoutManager() and EndpointConfiguration.UseExternalTimeoutManager() can safely be removed.

Data migration

Using a transport that previously relied on the timeout manager may require a migration of existing timeouts. Use the timeouts migration tool to detect and migrate timeouts as needed.

The following transports might need migration:

  • RabbitMQ
  • Azure Storage Queues
  • SQL Transport
  • SQS
  • MSMQ

Outbox configuration

NServiceBus version 8 requires the transport transaction mode to be set explicitly to ReceiveOnly when using the outbox feature:

var transport = endpointConfiguration.UseTransport<MyTransport>();

transport.TransportTransactionMode = TransportTransactionMode.ReceiveOnly;

endpointConfiguration.EnableOutbox();

AbortReceiveOperation

ITransportReceiveContext.AbortReceiveOperation has been deprecated in favor of throwing an OperationCanceledException. This will preserve the NServiceBus version 7 behavior of immediately retrying the message without invoking recoverability.

Renamed extension method types

The following static extension method types were renamed:

Old nameNew name
IEndpointInstanceExtensionsEndpointInstanceExtensions
IMessageProcessingExtensionsMessageProcessingExtensions
IMessageSessionExtensionsMessageSessionExtensions
IPipelineContextExtensionsPipelineContextExtensions

All references to the old types must be changed to the new types, although usually these types are not referenced, since they only contain extension methods.

Gateway in-memory deduplication

The InMemoryDeduplicationConfiguration type within the NServiceBus.Gateway package has been renamed to NonDurableDeduplicationConfiguration.

Dependency on System.Memory package for .NET Framework

Memory allocations for incoming and outgoing messages bodies are reduced by using the low allocation memory types via the System.Memory namespace. These type are available on .NET Framework via the System.Memory package. The NServiceBus build that targets .NET Framework has this dependency added.

Related Articles


Last modified