Host NServiceBus endpoints with Azure Functions and Azure Service Bus triggers.
Microsoft announced that .NET 8 will be the last release supporting the in-process hosting model. New projects should use the isolated worker model instead.
Basic usage
Endpoint configuration
NServiceBus can be registered and configured on the host builder using the UseNServiceBus
extension method in the startup class:
[assembly: FunctionsStartup(typeof(Startup))]
[assembly: NServiceBusTriggerFunction("MyFunctionsEndpoint")]
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.UseNServiceBus();
}
}
Additional configuration settings are retrieved from environment variables. See the configuration section for further details. All configuration settings can also be configured directly via code:
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.UseNServiceBus(configuration =>
{
configuration.Transport.SubscriptionNamingConvention = (name) => name.Replace("X", "Y");
});
}
}
Any services registered via the IFunctionsHostBuilder
will be available to message handlers via dependency injection. The startup class must be declared via the FunctionStartup
attribute: [assembly: FunctionsStartup(typeof(Startup))]
.
Azure Function queue trigger for NServiceBus
The Azure Function trigger for NServiceBus is auto-generated by specifying the logical endpoint name using a custom assembly attribute:
[assembly: NServiceBusTriggerFunction("MyFunctionsEndpoint")]
The attribute will generate the trigger function required for NServiceBus:
An invalid endpoint name will generate an NSBFUNC003
error with the message Endpoint name is invalid and cannot be used to generate trigger function
.
Overriding the trigger function name
The trigger function name is auto-generated by default. To customize the function name, the NServiceBusTriggerFunction
attribute can be provided with an additional parameter to set the function name:
[assembly: NServiceBusTriggerFunctionAttribute(EndpointName: "MyFunctionsEndpoint", TriggerFunctionName: "MyTriggerFunction")]
An invalid trigger function name will generate an NSBFUNC004
error with the message Trigger function name is invalid and cannot be used to generate trigger function
.
Customizing triggers
The Azure Service Bus trigger can be declared manually instead of relying on the auto-generated trigger. See the article on custom Azure Functions triggers for more information.
Dispatching outside a message handler
Triggering a message using HTTP function:
public class HttpSender
{
readonly IFunctionEndpoint functionEndpoint;
public HttpSender(IFunctionEndpoint functionEndpoint)
{
this.functionEndpoint = functionEndpoint;
}
[FunctionName("HttpSender")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest request, ExecutionContext executionContext, ILogger logger)
{
logger.LogInformation("C# HTTP trigger function received a request.");
var sendOptions = new SendOptions();
sendOptions.RouteToThisEndpoint();
await functionEndpoint.Send(new TriggerMessage(), sendOptions, executionContext, logger);
return new OkObjectResult($"{nameof(TriggerMessage)} sent.");
}
}
Transport configuration constraints and limitations
The configuration API exposes NServiceBus transport configuration options via the configuration.
property to allow customization. However, not all of the options will be applicable for execution within Azure Functions.
Concurrency-related settings are controlled via the Azure Function host.
configuration file. See Concurrency in Azure Functions for details.
Message consistency
NServiceBus can provide transactional consistency between incoming and outgoing messages:
[assembly: NServiceBusTriggerFunction("MyEndpoint", SendsAtomicWithReceive = true)]
This is equivalent to the SendsAtomicWithReceive
transport transaction mode. By default, transactional consistency is disabled, providing the same transport guarantees as the ReceiveOnly
transport transaction mode.
For more information on configuring message consistency using custom triggers, refer to the custom Azure Functions triggers documentation.
Microsoft.Azure.WebJobs.Extensions.ServiceBus Version 5 requires EnableCrossEntityTransactions
to be enabled in order to support sends atomic with receive.
This can be done by adding the following to host.
:
"extensions": {
"ServiceBus": {
"EnableCrossEntityTransactions": true
}
}
Configuration
ServiceBusTriggeredEndpointConfiguration
loads certain configuration values from the Azure Function host environment in the following order:
IConfiguration
passed in via the constructor- Environment variables
ServiceBus connection
When using the NServiceBusTriggerAttribute
, the connection to Azure Service Bus can be configured in multiple ways:
- Using just a
key, with the value set to the connection string for the ServiceBus namespace to connect to.<ConnectionName> - Using a
along with other connection properties prefixed by the same<CONNECTION_NAME_PREFIX>__fullyQualifiedNamespace
, as specified in the Identity Based Connections for Azure Functions.<CONNECTION_NAME_PREFIX>
If both a connection string and Identity Based connection values are specified, the connection string will take precedence. The default
or
is AzureWebJobsServiceBus
, however an alternate value can be supplied to the Connection
property on the NServiceBusTriggerAttribute
Example of a connection string based connection:
{
"IsEncrypted": false,
"Values": {
...
"AzureWebJobsServiceBus": "Endpoint=sb://<namespace>.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=<namespace-shared-access-key>",
}
}
Example of an Identity Based connection:
{
"IsEncrypted": false,
"Values": {
...
"MyConnectionName__fullyQualifiedNamespace": "<namespace>.servicebus.windows.net",
"MyConnectionName__tenantId": "00000000-0000-0000-0000-000000000000",
"MyConnectionName__clientId": "00000000-0000-0000-0000-000000000000",
"MyConnectionName__clientSecret": "<client-secret>"
}
}
[assembly: NServiceBusTriggerFunction("WorkerDemoEndpoint", Connection = "MyConnectionName")]
Other Configuration
Key | Value | Notes |
---|---|---|
ENDPOINT_NAME | The name of the NServiceBus endpoint to host | A value can be provided directly to the constructor. |
NSERVICEBUS_LICENSE | The NServiceBus license | Can also be provided via serviceBusTriggeredEndpointConfig. . |
WEBSITE_SITE_NAME | The name of the Azure Function app. Provided when hosting the function in Azure. | Used to set the NServiceBus host identifier. Local machine name is used if not set. |
For local development, use local.
. In Azure, specify a Function setting using the environment variable as the key.
{
"IsEncrypted": false,
"Values": {
...
"NSERVICEBUS_LICENSE": "<?xml version=\"1.0\" encoding=\"utf-8\"?><license id=\"1222e1d1-2222-4a46-b1c6-943c442ca710\" expiration=\"2113-11-30T00:00:00.0000000\" type=\"Standard\" LicenseType=\"Standard\" LicenseVersion=\"4.0\" MaxMessageThroughputPerSecond=\"Max\" WorkerThreads=\"Max\" AllowedNumberOfWorkerNodes=\"Max\">. . .</license>"
}
}
Custom diagnostics
NServiceBus startup diagnostics are disabled by default when using Azure Functions. Diagnostics can be written to the logs via the following snippet:
public override void Configure(IFunctionsHostBuilder builder)
{
builder.UseNServiceBus(configuration =>
{
configuration.LogDiagnostics();
});
}
Diagnostics data will be written with logger identification StartupDiagnostics
with log level Informational.
Error queue
For recoverability to move the continuously failing messages to the error queue rather than to the Azure Service Bus dead-letter queue, the error queue must be created in advance and configured using the following API:
class EnableDiagnosticsOnStartup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.UseNServiceBus(configuration =>
{
configuration.AdvancedConfiguration.SendFailedMessagesTo("error");
});
}
}
Preparing the Azure Service Bus namespace
Function endpoints cannot create their own queues or other infrastructure in the Azure Service Bus namespace.
Use the asb-transport
command line (CLI) tool to provision the entities in the namespace for the Function endpoint.
Creating the endpoint queue
asb-transport endpoint create <queue name>
See the full documentation for the asb-transport endpoint create
command for more details.
If the asb-tranport
command-line tool is not used to create the queue, it is recommended to set the MaxDeliveryCount
setting to the maximum value.
Subscribing to events
asb-transport endpoint subscribe <queue name> <eventtype>
See the full documentation for the asb-transport endpoint subscribe
command for more details.
Assembly scanning
Assembly scanning loads assemblies from two locations:
- The
bin
directory of the Azure Functions application - The Azure Functions runtime directory
If the same assembly is present in both locations, an exception is thrown which prevents the endpoint from running. Contact Particular Software support for assistance.
Package requirements
NServiceBus.
requires Visual Studio 2019 and .NET SDK version 5.
or higher. Older versions of the .NET SDK might display the following warning which prevents the trigger definition from being auto-generated:
CSC : warning CS8032: An instance of analyzer NServiceBus.AzureFunctions.SourceGenerator.TriggerFunctionGenerator cannot be created from NServiceBus.AzureFunctions.SourceGenerator.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.10.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified..
Starting in version 4.1.0 of NServiceBus.
and NServiceBus.
, warning CS8032 is treated as an error. To suppress this error, update the project's .csproj file to include the following line in the
section at the top:
<WarningsAsErrors></WarningsAsErrors>
This will revert CS8032 to a warning status so that it does not stop the build process.