Migrate .NET apps from the in-process model to the isolated worker model
This article walks you through the process of safely migrating your .NET function app from the in-process model to the isolated worker model. To learn about the high-level differences between these models, see the execution mode comparison.
This guide assumes that your app is running on version 4.x of the Functions runtime. If not, you should instead follow the guides for upgrading your host version:
- Migrate apps from Azure Functions version 2.x and 3.x to version 4.x
- Migrate apps from Azure Functions version 1.x to version 4.x
These host version migration guides will also help you migrate to the isolated worker model as you work through them.
Identify function apps to upgrade
Use the following Azure PowerShell script to generate a list of function apps in your subscription that currently use the in-process model.
The script uses subscription that Azure PowerShell is currently configured to use. You can change the subscription by first running Set-AzContext -Subscription '<YOUR SUBSCRIPTION ID>'
and replacing <YOUR SUBSCRIPTION ID>
with the ID of the subscription you would like to evaluate.
$FunctionApps = Get-AzFunctionApp
$AppInfo = @{}
foreach ($App in $FunctionApps)
{
if ($App.ApplicationSettings["FUNCTIONS_WORKER_RUNTIME"] -eq 'dotnet')
{
$AppInfo.Add($App.Name, $App.ApplicationSettings["FUNCTIONS_WORKER_RUNTIME"])
}
}
$AppInfo
Choose your target .NET version
On version 4.x of the Functions runtime, your .NET function app targets .NET 6 when using the in-process model.
When you migrate your function app, you have the opportunity to choose the target version of .NET. You can upgrade your C# project to one of the following versions of .NET that are supported by Functions version 4.x:
.NET version | .NET Official Support Policy release type | Functions process model1 |
---|---|---|
.NET 82 | LTS | Isolated worker model |
.NET 7 | STS (end of support May 14, 2024) | Isolated worker model |
.NET 6 | LTS (end of support November 12, 2024) | Isolated worker model, In-process model |
.NET Framework 4.8 | See policy | Isolated worker model |
1 The isolated worker model supports Long Term Support (LTS) and Standard Term Support (STS) versions of .NET, as well as .NET Framework. The in-process model only supports LTS releases of .NET. For a full feature and functionality comparison between the two models, see Differences between in-process and isolate worker process .NET Azure Functions.
2 .NET 8 is not yet supported on the in-process model, though it is available on the isolated worker model. For information about .NET 8 plans, including future options for the in-process model, see the Azure Functions Roadmap Update post.
Tip
We recommend upgrading to .NET 8 on the isolated worker model. This provides a quick upgrade path to the fully released version with the longest support window from .NET.
This guide doesn't present specific examples for .NET 7 or .NET 6. If you need to target these versions, you can adapt the .NET 8 examples.
Prepare for migration
If you haven't already, identify the list of apps that need to be migrated in your current Azure Subscription by using the Azure PowerShell.
Before you upgrade an app to the isolated worker model, you should thoroughly review the contents of this guide and familiarize yourself with the features of the isolated worker model and the differences between the two models.
To upgrade the application, you will:
- Complete the steps in Upgrade your local project to migrate your local project to the isolated worker model.
- After migrating your project, fully test the app locally using version 4.x of the Azure Functions Core Tools.
- Upgrade your function app in Azure to the isolated model.
Upgrade your local project
The section outlines the various changes that you need to make to your local project to move it to the isolated worker model. Some of the steps change based on your target version of .NET. Use the tabs to select the instructions which match your desired version. These steps assume a local C# project, and if your app is instead using C# script (.csx
files), you should convert to the project model before continuing.
Tip
If you are moving to an LTS or STS version of .NET, the .NET Upgrade Assistant can be used to automatically make many of the changes mentioned in the following sections.
First, you'll convert the project file and update your dependencies. As you do, you will see build errors for the project. In subsequent steps, you'll make the corresponding changes to remove these errors.
.csproj file
The following example is a .csproj
project file that uses .NET 6 on version 4.x:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<RootNamespace>My.Namespace</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
Use one of the following procedures to update this XML file to run in the isolated worker model:
These steps assume a local C# project, and if your app is instead using C# script (.csx
files), you should convert to the project model before continuing.
The following changes are required in the .csproj
XML project file:
Set the value of
PropertyGroup
.TargetFramework
tonet8.0
.Set the value of
PropertyGroup
.AzureFunctionsVersion
tov4
.Add the following
OutputType
element to thePropertyGroup
:<OutputType>Exe</OutputType>
In the
ItemGroup
.PackageReference
list, replace the package reference toMicrosoft.NET.Sdk.Functions
with the following references:<FrameworkReference Include="Microsoft.AspNetCore.App" /> <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.19.0" /> <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.4" /> <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.0.0" /> <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.21.0" /> <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.0.0" />
Make note of any references to other packages in the
Microsoft.Azure.WebJobs.*
namespaces. You'll replace these packages in a later step.Add the following new
ItemGroup
:<ItemGroup> <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext"/> </ItemGroup>
After you make these changes, your updated project should look like the following example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<RootNamespace>My.Namespace</RootNamespace>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.19.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.4" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.0.0" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.0.0" />
<!-- Other packages may also be in this list -->
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext"/>
</ItemGroup>
</Project>
Package references
When migrating to the isolated worker model, you need to change the packages your application references.
If you haven't already, update your project to reference the latest stable versions of:
Depending on the triggers and bindings your app uses, your app might need to reference a different set of packages. The following table shows the replacements for some of the most commonly used extensions:
Scenario | Changes to package references |
---|---|
Timer trigger | Add Microsoft.Azure.Functions.Worker.Extensions.Timer |
Storage bindings | ReplaceMicrosoft.Azure.WebJobs.Extensions.Storage with Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs, Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues, and Microsoft.Azure.Functions.Worker.Extensions.Tables |
Blob bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.Storage.Blobs with the latest version of Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs |
Queue bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.Storage.Queues with the latest version of Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues |
Table bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.Tables with the latest version of Microsoft.Azure.Functions.Worker.Extensions.Tables |
Cosmos DB bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.CosmosDB and/or Microsoft.Azure.WebJobs.Extensions.DocumentDB with the latest version of Microsoft.Azure.Functions.Worker.Extensions.CosmosDB |
Service Bus bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.ServiceBus with the latest version of Microsoft.Azure.Functions.Worker.Extensions.ServiceBus |
Event Hubs bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.EventHubs with the latest version of Microsoft.Azure.Functions.Worker.Extensions.EventHubs |
Event Grid bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.EventGrid with the latest version of Microsoft.Azure.Functions.Worker.Extensions.EventGrid |
SignalR Service bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.SignalRService with the latest version of Microsoft.Azure.Functions.Worker.Extensions.SignalRService |
Durable Functions | Replace references toMicrosoft.Azure.WebJobs.Extensions.DurableTask with the latest version of Microsoft.Azure.Functions.Worker.Extensions.DurableTask |
Durable Functions (SQL storage provider) |
Replace references toMicrosoft.DurableTask.SqlServer.AzureFunctions with the latest version of Microsoft.Azure.Functions.Worker.Extensions.DurableTask.SqlServer |
Durable Functions (Netherite storage provider) |
Replace references toMicrosoft.Azure.DurableTask.Netherite.AzureFunctions with the latest version of Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Netherite |
SendGrid bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.SendGrid with the latest version of Microsoft.Azure.Functions.Worker.Extensions.SendGrid |
Kafka bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.Kafka with the latest version of Microsoft.Azure.Functions.Worker.Extensions.Kafka |
RabbitMQ bindings | Replace references toMicrosoft.Azure.WebJobs.Extensions.RabbitMQ with the latest version of Microsoft.Azure.Functions.Worker.Extensions.RabbitMQ |
Dependency injection and startup config |
Remove references toMicrosoft.Azure.Functions.Extensions (The isolated worker model provides this functionality by default.) |
See Supported bindings for a complete list of extensions to consider, and consult each extension's documentation for full installation instructions for the isolated process model. Be sure to install the latest stable version of any packages you are targeting.
Your isolated worker model application should not reference any packages in the Microsoft.Azure.WebJobs.*
namespaces or Microsoft.Azure.Functions.Extensions
. If you have any remaining references to these, they should be removed.
Tip
Your app might also depend on Azure SDK types, either as part of your triggers and bindings or as a standalone dependency. You should take this opportunity to upgrade these as well. The latest versions of the Functions extensions work with the latest versions of the Azure SDK for .NET, almost all of the packages for which are the form Azure.*
.
Program.cs file
When migrating to run in an isolated worker process, you must add a Program.cs
file to your project with the following contents:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.Build();
host.Run();
The Program.cs
file will replace any file that has the FunctionsStartup
attribute, which is typically a Startup.cs
file. In places where your FunctionsStartup
code would reference IFunctionsHostBuilder.Services
, you can instead add statements within the .ConfigureServices()
method of the HostBuilder
in your Program.cs
. To learn more about working with Program.cs
, see Start-up and configuration in the isolated worker model guide.
Once you have moved everything from any existing FunctionsStartup
to the Program.cs
file, you can delete the FunctionsStartup
attribute and the class it was applied to.
Function signature changes
Some key types change between the in-process model and the isolated worker model. Many of these relate to the attributes, parameters, and return types that make up the function signature. For each of your functions, you must make changes to:
- The function attribute (which also sets the function's name)
- How the function obtains an
ILogger
/ILogger<T>
- Trigger and binding attributes and parameters
The rest of this section will walk you through each of these steps.
Function attributes
The FunctionName
attribute is replaced by the Function
attribute in the isolated worker model. The new attribute has the same signature, and the only difference is in the name. You can therefore just perform a string replacement across your project.
Logging
In the in-process model, you could include an additional ILogger
parameter to your function, or you could use dependency injection to get an ILogger<T>
. If you were already using dependency injection, the same mechanisms work in the isolated worker model.
However, for any Functions that relied on the ILogger
method parameter, you will need to make a change. It is recommended that you use dependency injection to obtain an ILogger<T>
. Use the following steps to migrate the function's logging mechanism:
In your function class, add a
private readonly ILogger<MyFunction> _logger;
property, replacingMyFunction
with the name of your function class.Create a constructor for your function class that takes in the
ILogger<T>
as a parameter:public MyFunction(ILogger<MyFunction> logger) { _logger = logger; }
Replace both instances of
MyFunction
in the code snippet above with the name of your function class.For logging operations in your function code, replace references to the
ILogger
parameter with_logger
.Remove the
ILogger
parameter from your function signature.
To learn more, see Logging in the isolated worker model.
Trigger and binding changes
When you changed your package references in a previous step, you introduced errors for your triggers and bindings that you will now fix:
Remove any
using Microsoft.Azure.WebJobs;
statements.Add a
using Microsoft.Azure.Functions.Worker;
statement.For each binding attribute, change the attribute's name as specified in its reference documentation, which you can find in the Supported bindings index. In general, the attribute names change as follows:
- Triggers typically remain named the same way. For example,
QueueTrigger
is the attribute name for both models. - Input bindings typically need "Input" added to their name. For example, if you used the
CosmosDB
input binding attribute in the in-process model, this would now beCosmosDBInput
. - Output bindings typically need "Output" added to their name. For example, if you used the
Queue
output binding attribute in the in-process model, this would now beQueueOutput
.
- Triggers typically remain named the same way. For example,
Update the attribute parameters to reflect the isolated worker model version, as specified in the binding's reference documentation.
For example, in the in-process model, a blob output binding is represented by a
[Blob(...)]
attribute that includes anAccess
property. In the isolated worker model, the blob output attribute would be[BlobOutput(...)]
. The binding no longer requires theAccess
property, so that parameter can be removed. So[Blob("sample-images-sm/{fileName}", FileAccess.Write, Connection = "MyStorageConnection")]
would become[BlobOutput("sample-images-sm/{fileName}", Connection = "MyStorageConnection")]
.Move output bindings out of the function parameter list. If you have just one output binding, you can apply this to the return type of the function. If you have multiple outputs, create a new class with properties for each output, and apply the attributes to those properties. To learn more, see Multiple output bindings.
Consult each binding's reference documentation for the types it allows you to bind to. In some cases, you might need to change the type. For output bindings, if the in-process model version used an
IAsyncCollector<T>
, you can replace this with binding to an array of the target type:T[]
. You can also consider replacing the output binding with a client object for the service it represents, either as the binding type for an input binding if available, or by injecting a client yourself.If your function includes an
IBinder
parameter, remove it. Replace the functionality with a client object for the service it represents, either as the binding type for an input binding if available, or by injecting a client yourself.Update the function code to work with any new types.
local.settings.json file
The local.settings.json file is only used when running locally. For information, see Local settings file.
When migrating from running in-process to running in an isolated worker process, you need to change the FUNCTIONS_WORKER_RUNTIME
value to "dotnet-isolated". Make sure that your local.settings.json file has at least the following elements:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
The value you have configured for `AzureWebJobsStorage`` might be different. You do not need to change its value as part of the migration.
Example function migrations
HTTP trigger example
An HTTP trigger for the in-process model might look like the following example:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
namespace Company.Function
{
public static class HttpTriggerCSharp
{
[FunctionName("HttpTriggerCSharp")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
return new OkObjectResult($"Welcome to Azure Functions, {req.Query["name"]}!");
}
}
}
An HTTP trigger for the migrated version might like the following example:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace Company.Function
{
public class HttpTriggerCSharp
{
private readonly ILogger<HttpTriggerCSharp> _logger;
public HttpTriggerCSharp(ILogger<HttpTriggerCSharp> logger)
{
_logger = logger;
}
[Function("HttpTriggerCSharp")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
return new OkObjectResult($"Welcome to Azure Functions, {req.Query["name"]}!");
}
}
}
Upgrade your function app in Azure
Upgrading your function app to the isolated model consists of two steps:
- Change the configuration of the function app to use the isolated model by setting the
FUNCTIONS_WORKER_RUNTIME
application setting to "dotnet-isolated". Make sure that any deployment automation is similarly updated. - Publish your upgraded project to the upgraded function app.
When you use Visual Studio to publish an isolated worker model project to an existing function app that uses the in-process model, you're prompted to let Visual Studio upgrade the function app during deployment. This accomplishes both steps at once.
If you need to minimize downtime, consider using a staging slot to test and verify your upgraded code with your upgraded configuration in Azure. You can then deploy your upgraded app to the production slot through a swap operation.
Once you've completed these steps, your app has been fully migrated to the isolated model. Congratulations! Repeat the steps from this guide as necessary for any other apps needing migration.
Next steps
Feedback
Submit and view feedback for