| Branch | Status |
|---|---|
| main |
Welcome to the Azure Functions .NET Worker Repository. Azure Functions' Isolated Worker Model is the recommended model for .NET functions. It moves function execution into a separate language worker process, giving you full control over your application's dependencies and enabling advanced .NET features such as middleware and dependency injection.
With the Isolated Worker Model, you build an executable that imports the .NET Isolated language worker as a NuGet package. Your app includes a Program.cs that starts the worker.
.NET Isolated introduces a new binding model, slightly different from the binding model exposed in .NET in-process Azure Functions. More information can be found here. Please review our samples for usage information.
The Azure Functions .NET Isolated supports middleware registration, following a model similar to what exists in ASP.NET and giving you the ability to inject logic into the invocation pipeline, pre and post function executions.
You can find samples on how to use different features of the .NET Worker under samples (link).
Please see our Guide for running C# Azure Functions in an isolated worker process for information on how to develop, debug and deploy using the Isolated Worker model.
The normal gRPC worker advertises ExtensionPayload="1" on .NET 7 and later. The capability is set once in WorkerOptions.Capabilities after resolving the client, based only on transport support. Initialization and environment reload do not inspect payload paths, open files, enumerate directories, or create an archive. The capability is not a promise that deployment files are available or an instruction to send; a worker sends no payload without an explicit Host request.
Only when requested, the worker resolves the application directory once and retains it for the process lifetime. Resolution prefers FUNCTIONS_APPLICATION_DIRECTORY when nonempty and non-whitespace, otherwise falling back to AppContext.BaseDirectory. An explicitly configured directory is not replaced if files are missing or inaccessible. Missing, malformed, or inaccessible payload inputs fail that request with a correlated terminal failure and local diagnostics, not worker initialization.
The Host requests a payload while acquiring its first accepted extension source, then reuses that source for later or concurrent worker links instead of requesting or comparing additional payloads. Later workers may still advertise support; the Host decides whether acquisition is needed.
ExtensionPayloadRequest on the existing EventStream creates a temporary ZIP containing the root manifest and recursive .azurefunctions assets. The provider removes the SDK-owned Host metadata-loader startup from the archived extensions.json and excludes only its known root Microsoft.Azure.WebJobs.Extensions.FunctionMetadataLoader.dll and .pdb files. Deployment originals and ordinary co-located build/publish output are not changed, and no SDK opt-out is required. Other manifest fields, entries, hints, real extension assets, and shared dependencies are preserved; an already-filtered manifest is copied unchanged.
Payload provision is separate from delivery. IExtensionPayloadProvider.OpenReadAsync returns an owned readable stream without depending on the worker client or protobuf messages. ExtensionPayloadHandler owns request coordination, chunk framing, awaited transport writes, and disposal of that stream. It does not require seeking, a known length, or a file-backed stream, so a future provider can open a build-produced ZIP without changing delivery.
Discovered nested links are skipped without traversal, and linked root inputs are rejected. Each ZIP is created in a private temporary directory with owner-only permissions on Unix; disposing the archive stream removes both the ZIP and directory. The limits are 256 MiB compressed, 1 GiB of archived file contents, 1 MiB each for manifest input and filtered output, 10,000 filesystem entries including implicit directories, and 32 path segments. Malformed or oversized manifests fail the request and remove their temporary artifacts. The archive has no comment or ZIP64 end records.
The manifest input buffer starts at the file's reported length plus one byte and grows only if needed. The input limit is enforced against actual bytes read, including when a file grows after its length is checked.
Responses share the request's outer request_id. Chunks contain at most 64 KiB, fit the configured protobuf-envelope limit, and have cumulative byte offsets. A live transfer ends with one success or failure result. Cancellation belongs to connection loss or worker shutdown; there is no payload-cancellation message or recoverable per-request cancellation on the same link. Shutdown cancels preparation or sending and drains in-flight writes before releasing the temporary ZIP. No terminal response is required on a closed or shutting-down connection. Payload writes await the actual serialized gRPC write, not admission to the logging queue. If terminal delivery also fails after a payload or cleanup failure, both failures are retained locally.
The gRPC client is one-shot. Startup failure, startup cancellation, either message loop ending, and explicit shutdown use the same idempotent termination path to close the output writer, cancel the connection, and dispose the RPC call. Loop draining and startup-registration cleanup are separate, so a loop never waits for itself. Cleanup failures from both published and startup-owned RPC calls are included in shutdown completion. Once terminated, the client rejects new queued messages; shutdown aborts the connection rather than promising delivery of all queued messages. As before, shutdown waits for owned operations to finish even if its caller's shutdown token expires.
Native-host workers do not advertise this capability: their current ABI reports queue admission rather than transport completion. The .NET 6 and .NET Standard 2.0 assets also do not advertise payload support because private temporary directory creation requires .NET 7+. These workers retain ordinary transport behavior and reject unexpected payload requests without preparing a ZIP. No new RPC service or HTTP download is introduced.
Worker indexing passes the resolved application directory to its metadata provider, including the functions.metadata fallback provider, rather than using the Host-supplied directory. Function assembly loading, host configuration delivery, and ASP.NET Core endpoint discovery use the same resolution policy. FUNCTIONS_WORKER_DIRECTORY is no longer used as a fallback for function assembly loading. The Host and WorkerProxy do not gain access to these files.
- Powershell 7
- CosmosDb Emulator
- Azurite (the set up script will download this automatically)
- Run
setup-e2e-tests.ps1. Once the build succeeds and the emulators are started correctly, you are done with the setup. - Run
run-e2e-tests.ps1to run the tests or use the Test Explorer in VS.
Note: Do not add the switch to skip the core-tools download when running set-up-e2e-tests.ps1 as it will lead to an incomplete setup.
-
To deploy the app, first ensure that you've installed the Azure CLI.
-
Login to the CLI.
az login
-
If necessary, use
az account setto select the subscription you want to use. -
Create a resource group, Storage account, and Azure Functions app. If you would like to use an existing Azure Functions app, please skip this step.
az group create --name AzureFunctionsQuickstart-rg --location westeurope az storage account create --name <STORAGE_NAME> --location westeurope --resource-group AzureFunctionsQuickstart-rg --sku Standard_LRS az functionapp create --resource-group AzureFunctionsQuickstart-rg --consumption-plan-location westeurope --runtime dotnet-isolated --functions-version 4 --name <APP_NAME> --storage-account <STORAGE_NAME>
-
Ensure you are in your functions project folder.
-
Deploy the app.
func azure functionapp publish <APP_NAME>
Please create issues in this repo. Thanks!
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
