(2022-09-12 - we've posted a new update that builds upon this one. See the latest update.)
Today, we announced support for running production .NET 5 apps on Azure Functions. With this release, we now support running .NET functions in a standalone process. Running in an isolated process decouples .NET functions from the Azure Functions host—allowing us to more easily support new .NET versions and address pain points associated with sharing a single process. However, creating this new isolated process model required significant effort and we were unable to immediately support .NET 5. This delay was not due to lack of planning or prioritization, but we understand the frustration from those of you who wished to move application architectures to the latest bits and weren't able to do so until Azure Functions could run .NET 5.
One of our learnings during this release was the need for us to be more proactive and open about our plans and roadmap, specifically with .NET. In this post we’ll go into details on this new isolated process model for .NET function apps and share our roadmap for supporting future versions of .NET.
.NET isolated process—a new way to run .NET on Azure Functions
The Azure Functions host is the runtime that powers Azure Functions and runs on .NET and .NET Core. Since the beginning, .NET and .NET Core function apps have run in the same process as the host. Sharing a process has enabled us to provide some unique benefits to .NET functions, most notably is a set of rich bindings and SDK injections. A .NET developer is able to trigger or bind directly to the SDKs and types used in the host process—including advanced types like CloudBlockBlob from the Storage SDK or Message from the Service Bus SDK—allowing users to do more in .NET functions with less code.
However, sharing the same process does come with some tradeoffs. In earlier versions of Azure Functions, dependencies could conflict (notable conflicting libraries include Newtonsoft.Json). While flexibility of packages was largely addressed in Azure Functions V2 and beyond, there are still restrictions on how much of the process is customizable by the user. Running in the same process also means that the .NET version of user code must match the .NET version of the host. These tradeoffs of sharing a process motivated us to choose an out-of-process model for .NET 5.
Other languages supported by Azure Functions use an out-of-process model that runs a language worker in a separate, isolated process from the main Azure Functions host. This allows Azure Functions to rapidly support new versions of these languages without updating the host, and it allows the host to evolve independently to enable new features and update its own dependencies over time.
Today’s .NET 5 release is our first iteration of running .NET in a separate process. With .NET now following an annual release cadence and .NET 5 not being a long-term supported (LTS) release, we decided this is the right time to begin this journey.
A .NET 5 function app runs in an isolated worker process. Instead of building a .NET library loaded by our host, you build a .NET console app that references a worker SDK. This brings immediate benefits: you have full control over the application’s startup and the dependencies it consumes. The new programming model also adds support for custom middleware which has been a frequently requested feature.
While this isolated model for .NET brings the above benefits, it’s worth noting there are some features you may have utilized in previous versions that aren’t yet supported. While the .NET isolated model supports most Azure Functions triggers and bindings, Durable Functions and rich types support are currently unavailable. Take a blob trigger for example, you are limited to passing blob content using data types that are supported in the out-of-process language worker model, which today are string, byte, and POCO. You can still use Azure SDK types like CloudBlockBlob, but you’ll need to instantiate the SDK in your function process.
Many of these temporary gaps will close as the new isolated model continues to evolve. However, there are no current plans to close any of these gaps in the .NET 5 timeframe. They will more likely will land in 2022. If any of these limitations are blocking, we recommend you continue to use .NET Core 3.1 in the in-process model.
.NET 5 on Azure Functions
You can run .NET 5 on Azure Functions in production today using the .NET isolated worker. Currently, full tooling support is available in Azure CLI, Azure Functions Core Tools, and Visual Studio Code. You can edit and debug .NET 5 projects in Visual Studio; full support is in progress and estimated to be available in a couple of months.
Future of .NET on Azure Functions
One of the most frequent pieces of feedback we’ve received is that Azure Functions needs to support new versions of .NET as soon as they’re available. We agree, and we have a plan to provide day 1 support for future LTS and non-LTS .NET versions.
.NET 6 LTS
.NET 6 functions will support both in-process and isolated process options. The in-process option will support the full feature set available in .NET Core 3.1 functions today, including Durable Functions and rich binding types. The isolated process option will provide an upgrade path for apps using this option for .NET 5 and initially will have the same feature set and limitations.
A few weeks ago, the .NET team released the first preview of .NET 6. In the first half of 2021, we will deliver a version of the Azure Functions host for running functions on .NET 6 preview using the in-process model. The initial preview of .NET 6 on Azure Functions will run locally and in containers. In the summer, we expect .NET 6 preview to be available on our platform and you’ll be able to deploy .NET 6 preview function apps without the use of containers.
On the same day .NET 6 LTS reaches general availability in November, you’ll be able to deploy and run .NET 6 Azure Functions.
.NET 7 and beyond
Long term, our vision is to have full feature parity out of process, bringing many of the features that are currently exclusive to the in-process model to the isolated model. We plan to begin delivering improvements to the isolated model after the .NET 6 general availability release.
.NET 7 is scheduled for the second half of 2022, and we plan to support .NET 7 on day 1 exclusively in the isolated model. We expect that you’ll be able to migrate and run almost any .NET serverless workload in the isolated worker—including Durable Functions and other targeted improvements to the isolated model.
Currently, .NET Framework is supported in the Azure Functions V1 host. As the isolated model for .NET continues to evolve, we will investigate the feasibility of running the .NET isolated worker SDK in .NET Framework apps. This could allow users to develop apps targeting .NET Framework on newer versions of the functions runtime.
We are thrilled by the adoption and solutions we see running on Azure Functions today, accounting for billions of function executions every day. We are deeply grateful for the .NET community, many of you have been with us since day 1. Our hope is that this post gives clarity on our plans for supporting future versions of .NET on Azure Functions and evolving the programming model. Supporting our differentiated features while removing the constraints of the in-process model is a non-trivial task, and we plan to be open and communicative throughout the journey. We’ll be conducting a special .NET roadmap webcast on March 25 where we will make time to answer any questions you may have.
To get started building Azure Functions in .NET 5, check out Develop and publish .NET 5 functions.