Microsoft has confirmed that .NET 8.0 will be the last LTS to support the in-process hosting model and .NET 6.0 LTS will reach end of support in November 2024. Migrating to the isolated worker hosting model is strongly advised.
When migrating from the in-process model to the isolated worker model, it is highly recommended that you follow Microsoft's migration guide to start with, as this guide specifically covers the NServiceBus functionality.
Key differences
Find more detailed information about the difference between the in-process and isolated worker model.
- In-process: Functions run within the Azure Functions runtime, share the same process an AppDomain.
- Isolated worker: Functions are isolated from the Azure Functions runtime and run in a separate process.
Update project file
Framework
It's recommended to update the TargetFramework
in your .
file to net8.
.
Package references
- Remove
NServiceBus.
from yourAzureFunctions. InProcess. ServiceBus .
file.csproj - Add
NServiceBus.
to yourAzureFunctions. Worker. ServiceBus .
file with the appropriate version based on the version of NServiceBus in your project.csproj
Update host configuration
A Program.
file is required and replaces any file that has the FunctionsStartup attribute like the Startup.
when migrating to the isolated worker model.
This is an example of and in-process host configuration using Startup.
[assembly: FunctionsStartup(typeof(Startup))]
[assembly: NServiceBusTriggerFunction(Startup.EndpointName)]
class Startup : FunctionsStartup
{
public const string EndpointName = "DemoEndpoint";
public override void Configure(IFunctionsHostBuilder builder)
{
builder.UseNServiceBus();
}
}
A migrated host configuration for isolated worker to Program.
would look like the following
[assembly: NServiceBusTriggerFunction(Program.EndpointName)]
public class Program
{
public const string EndpointName = "DemoEndpoint";
public static Task Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.UseNServiceBus()
.Build();
return host.RunAsync();
}
}
Update trigger functions
Remember first to follow Microsoft's migration guide to update the trigger functions and bindings.
Trigger function signature and logic
- Change
ExecutionContext
parameter toFunctionContext
- The logger can be accessed through the
FunctionContext
- The
functionEndpoint.
method no longer takes the logger as a parameter.Send - Update the trigger function annotation from
[FunctionName(
to<triggerFunctionName>) [Function(
<triggerFunctionName>)]
An example of an in-process trigger 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.");
}
}
This is an example of a trigger function migrated to the isolated worker model
class HttpSender
{
readonly IFunctionEndpoint functionEndpoint;
public HttpSender(IFunctionEndpoint functionEndpoint)
{
this.functionEndpoint = functionEndpoint;
}
[Function("HttpSender")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestData req, FunctionContext functionContext)
{
var logger = functionContext.GetLogger<HttpSender>();
logger.LogInformation("C# HTTP trigger function received a request.");
var sendOptions = new SendOptions();
sendOptions.RouteToThisEndpoint();
await functionEndpoint.Send(new TriggerMessage(), sendOptions, functionContext);
var r = req.CreateResponse(HttpStatusCode.OK);
await r.WriteStringAsync($"{nameof(TriggerMessage)} sent.");
return r;
}
}
Ensuring consistency in the Isolated Worker model
If SendsAtomicWithReceive
was previously enabled in the in-process model (note that it is not enabled by default), maintaining that consistency guarantee in the isolated worker model is important.
Lower transaction modes can result in the duplication of outgoing messages otherwise known as ghost messages. To ensure that consistency is maintained make sure that all involved message handlers are idempotent.
Using SendsAtomicWithReceive in the In-Process model
In the in-process model, SendsAtomicWithReceive
could be enabled by setting a boolean value to true in the assembly attribute:
[assembly: NServiceBusTriggerFunction("ASBFunctionEndpoint", SendsAtomicWithReceive = true)]
Changes in the Isolated Worker model
In the isolated worker model, the SendsAtomicWithReceive
attribute is not supported. This is because the Microsoft.
cannot natively manage transactions across the separate processes that run the function code and the host runtime. Unlike the in-process model, where the function code and the host runtime share the same process, making transaction management more feasible, the isolated worker model requires this setting to be removed from the assembly attribute.
[assembly: NServiceBusTriggerFunction("ASBFunctionEndpoint")]