NServiceBus endpoints can be hosted in an Azure Functions app using the NServiceBus. package.
Integration is enabled in Program. by calling AddNServiceBusFunctions:
var builder = FunctionsApplication.CreateBuilder(args);
builder.AddNServiceBusFunctions();
var host = builder.Build();
await host.RunAsync();
Endpoints are declared using the [NServiceBusFunction] attribute:
public partial class OrdersEndpoint
{
[Function("Orders")]
[NServiceBusFunction]
public partial Task Orders(
[ServiceBusTrigger("orders", AutoCompleteMessages = false)]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions,
FunctionContext functionContext,
CancellationToken cancellationToken = default);
public static void ConfigureOrders(EndpointConfiguration endpointConfiguration)
{
endpointConfiguration.UseTransport(new AzureServiceBusServerlessTransport(TopicTopology.Default));
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.AddHandler<PlaceOrderHandler>();
}
}
NServiceBus enabled functions must be declared in a partial class and are composed of two parts:
- A partial method decorated with a
[NServiceBusFunction]and a[Function("MyFunction")]attribute declaring an Azure Service Bus trigger.- The trigger must set
AutoCompleteMessages = falsesince the NServiceBus pipeline takes responsibility for completing or abandoning each message based on handler outcomes; theNSBFUNC005analyzer enforces this requirement. - A source generator will emit the method body that forwards each incoming message to the NServiceBus pipeline.
- The trigger must set
- A static
Configure{FunctionName}method that configures the NServiceBus endpoint for the function.
For endpoint configuration, supported transport options, and explicit handler and saga registration, etc, see Configuration.
Hosting multiple endpoints
Multiple methods decorated with [NServiceBusFunction] can co-exist in one Functions app. Each is registered as an independent NServiceBus endpoint with its own queue, handlers, and configure method:
public partial class BillingFunctions
{
[Function("Invoicing")]
[NServiceBusFunction]
public partial Task Invoicing(
[ServiceBusTrigger("billing-invoicing", AutoCompleteMessages = false)]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions,
FunctionContext functionContext,
CancellationToken cancellationToken = default);
public static void ConfigureInvoicing(EndpointConfiguration endpointConfiguration)
{
endpointConfiguration.UseTransport(new AzureServiceBusServerlessTransport(TopicTopology.Default));
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.AddHandler<ProcessPaymentHandler>();
}
[Function("CardProcessing")]
[NServiceBusFunction]
public partial Task CardProcessing(
[ServiceBusTrigger("billing-card-processing", AutoCompleteMessages = false)]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions,
FunctionContext functionContext,
CancellationToken cancellationToken = default);
public static void ConfigureCardProcessing(EndpointConfiguration endpointConfiguration)
{
endpointConfiguration.UseTransport(new AzureServiceBusServerlessTransport(TopicTopology.Default));
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.AddHandler<PaymentChargedHandler>();
}
}
Each endpoint has its own Configure{FunctionName} method; the source generator routes each function to its matching configure method. Endpoints share the host's service provider but maintain independent message-handling pipelines.
Send-only endpoints
A send-only endpoint can be declared for components that need to dispatch messages without receiving incoming messages. Send-only endpoints can be used, for example, from a TimerTrigger or an HttpTrigger function serving as an HTTP API:
[NServiceBusSendOnlyFunction("client")]
public static void ConfigureClient(EndpointConfiguration endpointConfiguration, IServiceCollection services)
{
services.AddSingleton(new MyComponent("client"));
var transport = new AzureServiceBusServerlessTransport(TopicTopology.Default);
var routing = endpointConfiguration.UseTransport(transport);
routing.RouteToEndpoint(typeof(SubmitOrder), "sales");
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
}
The attribute name becomes the keyed-services key used to resolve IMessageSession and any endpoint-scoped services. Set the optional Connection property to override the default connection setting name.
Send-only endpoints are discovered and registered automatically by builder..
class SalesApi([FromKeyedServices("client")] IMessageSession session, [FromKeyedServices("client")] MyComponent component)
{
[Function("SalesApi")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData request)
{
await session.Send(new SubmitOrder());
var response = request.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync(component.EndpointName);
return response;
}
}