Create your first Durable Function in C#

Durable Functions is an extension of Azure Functions that lets you write stateful functions in a serverless environment. The extension manages state, checkpoints, and restarts for you.

Like Azure Functions, Durable Functions supports two process models for .NET class library functions:

Execution model Description
Isolated worker model Your function code runs in a separate .NET worker process. Use with supported versions of .NET and .NET Framework. To learn more, see Develop .NET isolated worker process functions.
In-process model Your function code runs in the same process as the Functions host process. Supports only Long Term Support (LTS) versions of .NET. To learn more, see Develop .NET class library functions.

To learn more about the two processes, refer to Differences between in-process and isolated worker process .NET Azure Functions.

In this article, you learn how to use Visual Studio Code to locally create and test a "hello world" durable function. This function orchestrates and chains together calls to other functions. You can then publish the function code to Azure. These tools are available as part of the Visual Studio Code Azure Functions extension.

Screenshot of Visual Studio Code window with a durable function.

Prerequisites

To complete this tutorial:

If you don't have an Azure subscription, create an Azure free account before you begin.

Create your local project

In this section, you use Visual Studio Code to create a local Azure Functions project.

  1. In Visual Studio Code, press F1 (or Ctrl/Cmd+Shift+P) to open the command palette. In the command palette, search for and select Azure Functions: Create New Project....

    Screenshot of create a function project window.

  2. Choose an empty folder location for your project and choose Select.

  3. Follow the prompts and provide the following information:

    Prompt Value Description
    Select a language for your function app project C# Create a local C# Functions project.
    Select a version Azure Functions v4 You only see this option when the Core Tools aren't already installed. In this case, Core Tools are installed the first time you run the app.
    Select a .NET runtime .NET 7.0 isolated Creates a function project that supports .NET 7 running in isolated worker process and the Azure Functions Runtime 4.0. For more information, see How to target Azure Functions runtime version.
    Select a template for your project's first function Skip for now
    Select how you would like to open your project Open in current window Reopens Visual Studio Code in the folder you selected.

Visual Studio Code installs the Azure Functions Core Tools if needed. It also creates a function app project in a folder. This project contains the host.json and local.settings.json configuration files.

Add NuGet package references

Add the following to your app project:

<ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.1" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.4" OutputItemType="Analyzer" />
</ItemGroup>

Add functions to the app

The most basic Durable Functions app contains the following three functions. Add them to a new class in the app:

using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.Extensions.Logging;

static class HelloSequence
{
    [Function(nameof(HelloCities))]
    public static async Task<string> HelloCities([OrchestrationTrigger] TaskOrchestrationContext context)
    {
        string result = "";
        result += await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo") + " ";
        result += await context.CallActivityAsync<string>(nameof(SayHello), "London") + " ";
        result += await context.CallActivityAsync<string>(nameof(SayHello), "Seattle");
        return result;
    }

    [Function(nameof(SayHello))]
    public static string SayHello([ActivityTrigger] string cityName, FunctionContext executionContext)
    {
        ILogger logger = executionContext.GetLogger(nameof(SayHello));
        logger.LogInformation("Saying hello to {name}", cityName);
        return $"Hello, {cityName}!";
    }

    [Function(nameof(StartHelloCities))]
    public static async Task<HttpResponseData> StartHelloCities(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
        [DurableClient] DurableTaskClient client,
        FunctionContext executionContext)
    {
        ILogger logger = executionContext.GetLogger(nameof(StartHelloCities));

        string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(HelloCities));
        logger.LogInformation("Created new orchestration with instance ID = {instanceId}", instanceId);

        return client.CreateCheckStatusResponse(req, instanceId);
    }
}
Method Description
HelloCities Manages the durable orchestration. In this case, the orchestration starts, creates a list, and adds the result of three functions calls to the list. When the three function calls are complete, it returns the list.
SayHello The function returns a hello. It's the function that contains the business logic that is being orchestrated.
StartHelloCities An HTTP-triggered function that starts an instance of the orchestration and returns a check status response.

Configure storage

Your app needs a storage for runtime information. To use Azurite, which is an emulator for Azure Storage, set AzureWebJobStorage in local.settings.json to UseDevelopmentStorage=true:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  }
}

You can install the Azurite extension on Visual Studio Code and start it by running Azurite: Start in the command palette.

There are other storage options you can use for your Durable Functions app. See Durable Functions storage providers to learn more about different storage options and what benefits they provide.

Test the function locally

Azure Functions Core Tools lets you run an Azure Functions project locally. You're prompted to install these tools the first time you start a function from Visual Studio Code.

  1. To test your function, set a breakpoint in the SayHello activity function code and press F5 to start the function app project. Output from Core Tools is displayed in the Terminal panel.

    Note

    For more information on debugging, see Durable Functions Diagnostics.

  2. In the Terminal panel, copy the URL endpoint of your HTTP-triggered function.

    Screenshot of Azure local output window.

  3. Use a tool like Postman or cURL, and then send an HTTP POST request to the URL endpoint.

    The response is the HTTP function's initial result, letting us know that the durable orchestration has started successfully. It isn't yet the end result of the orchestration. The response includes a few useful URLs. For now, let's query the status of the orchestration.

  4. Copy the URL value for statusQueryGetUri, paste it into the browser's address bar, and execute the request. Alternatively, you can also continue to use Postman to issue the GET request.

    The request will query the orchestration instance for the status. You must get an eventual response, which shows us that the instance has completed and includes the outputs or results of the durable function. It looks like:

    {
        "name":"HelloCities",
        "instanceId":"7f99f9474a6641438e5c7169b7ecb3f2",
        "runtimeStatus":"Completed",
        "input":null,
        "customStatus":null,
        "output":"Hello, Tokyo! Hello, London! Hello, Seattle!",
        "createdTime":"2023-01-31T18:48:49Z",
        "lastUpdatedTime":"2023-01-31T18:48:56Z"
    }
    
  5. To stop debugging, press Shift + F5 in Visual Studio Code.

After you've verified that the function runs correctly on your local computer, it's time to publish the project to Azure.

Sign in to Azure

Before you can create Azure resources or publish your app, you must sign in to Azure.

  1. If you aren't already signed in, choose the Azure icon in the Activity bar. Then in the Resources area, choose Sign in to Azure....

    Screenshot of the sign-in to Azure window within VS Code.

    If you're already signed in and can see your existing subscriptions, go to the next section. If you don't yet have an Azure account, choose Create an Azure Account.... Students can choose Create an Azure for Students Account....

  2. When prompted in the browser, choose your Azure account and sign in using your Azure account credentials. If you create a new account, you can sign in after your account is created.

  3. After you've successfully signed in, you can close the new browser window. The subscriptions that belong to your Azure account are displayed in the sidebar.

Create the function app in Azure

In this section, you create a function app and related resources in your Azure subscription.

  1. Choose the Azure icon in the Activity bar. Then in the Resources area, select the + icon and choose the Create Function App in Azure option.

    Create a resource in your Azure subscription

  2. Provide the following information at the prompts:

    Prompt Selection
    Select subscription Choose the subscription to use. You won't see this prompt when you have only one subscription visible under Resources.
    Enter a globally unique name for the function app Type a name that is valid in a URL path. The name you type is validated to make sure that it's unique in Azure Functions.
    Select a runtime stack Choose the language version on which you've been running locally.
    Select a location for new resources For better performance, choose a region near you.

    The extension shows the status of individual resources as they're being created in Azure in the Azure: Activity Log panel.

    Log of Azure resource creation

  3. When the creation is complete, the following Azure resources are created in your subscription. The resources are named based on your function app name:

    • A resource group, which is a logical container for related resources.
    • A standard Azure Storage account, which maintains state and other information about your projects.
    • A function app, which provides the environment for executing your function code. A function app lets you group functions as a logical unit for easier management, deployment, and sharing of resources within the same hosting plan.
    • An App Service plan, which defines the underlying host for your function app.
    • An Application Insights instance connected to the function app, which tracks usage of your functions in the app.

    A notification is displayed after your function app is created and the deployment package is applied.

    Tip

    By default, the Azure resources required by your function app are created based on the function app name you provide. By default, they're also created in the same new resource group with the function app. If you want to either customize the names of these resources or reuse existing resources, you need to publish the project with advanced create options instead.

Deploy the project to Azure

Important

Deploying to an existing function app always overwrites the contents of that app in Azure.

  1. In the Resources area of the Azure activity, locate the function app resource you just created, right-click the resource, and select Deploy to function app....

  2. When prompted about overwriting previous deployments, select Deploy to deploy your function code to the new function app resource.

  3. After deployment completes, select View Output to view the creation and deployment results, including the Azure resources that you created. If you miss the notification, select the bell icon in the lower right corner to see it again.

    Screenshot of the View Output window.

Test your function in Azure

  1. Copy the URL of the HTTP trigger from the Output panel. The URL that calls your HTTP-triggered function must be in the following format:

    https://<functionappname>.azurewebsites.net/api/HelloOrchestration_HttpStart

  2. Paste this new URL for the HTTP request into your browser's address bar. You must get the same status response as before when using the published app.

Next steps

You have used Visual Studio Code to create and publish a C# durable function app.

In this article, you will learn how to use Visual Studio 2022 to locally create and test a "hello world" durable function that run in the isolated worker process. This function orchestrates and chains-together calls to other functions. You then publish the function code to Azure. These tools are available as part of the Azure development workload in Visual Studio 2022.

Screenshot of Visual Studio 2019 window with a durable function.

Prerequisites

To complete this tutorial:

  • Install Visual Studio 2022. Make sure that the Azure development workload is also installed. Visual Studio 2019 also supports Durable Functions development, but the UI and steps differ.

  • Verify that you have the Azurite Emulator installed and running.

If you don't have an Azure subscription, create an Azure free account before you begin.

Create a function app project

The Azure Functions template creates a project that can be published to a function app in Azure. A function app lets you group functions as a logical unit for easier management, deployment, scaling, and sharing of resources.

  1. In Visual Studio, select New > Project from the File menu.

  2. In the Create a new project dialog, search for functions, choose the Azure Functions template, and then select Next.

    Screenshot of new project dialog in Visual Studio.

  3. Enter a Project name for your project, and select OK. The project name must be valid as a C# namespace, so don't use underscores, hyphens, or nonalphanumeric characters.

  4. Under Additional information, use the settings specified in the table that follows the image.

    Screenshot of create a new Azure Functions Application dialog in Visual Studio.

    Setting Suggested value Description
    Functions worker .NET 7 Isolated Creates a function project that supports .NET 7 running in isolated worker process and the Azure Functions Runtime 4.0. For more information, see How to target Azure Functions runtime version.
    Function Empty Creates an empty function app.
    Storage account Storage Emulator A storage account is required for durable function state management.
  5. Select Create to create an empty function project. This project has the basic configuration files needed to run your functions. Make sure the box for "Use Azurite for runtime storage account (AzureWebJobStorage)" is checked. This will use Azurite emulator.

Note that there are other storage options you can use for your Durable Functions app. See Durable Functions storage providers to learn more about different storage options and what benefits they provide.

Add NuGet package references

Add the following to your app project:

<ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.1" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.4" OutputItemType="Analyzer" />
</ItemGroup>

Add functions to the app

The most basic Durable Functions app contains the following three functions. Add them to a new class in the app:

using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.Functions.Worker;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.Extensions.Logging;

static class HelloSequence
{
    [Function(nameof(HelloCities))]
    public static async Task<string> HelloCities([OrchestrationTrigger] TaskOrchestrationContext context)
    {
        string result = "";
        result += await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo") + " ";
        result += await context.CallActivityAsync<string>(nameof(SayHello), "London") + " ";
        result += await context.CallActivityAsync<string>(nameof(SayHello), "Seattle");
        return result;
    }

    [Function(nameof(SayHello))]
    public static string SayHello([ActivityTrigger] string cityName, FunctionContext executionContext)
    {
        ILogger logger = executionContext.GetLogger(nameof(SayHello));
        logger.LogInformation("Saying hello to {name}", cityName);
        return $"Hello, {cityName}!";
    }

    [Function(nameof(StartHelloCities))]
    public static async Task<HttpResponseData> StartHelloCities(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
        [DurableClient] DurableTaskClient client,
        FunctionContext executionContext)
    {
        ILogger logger = executionContext.GetLogger(nameof(StartHelloCities));

        string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(nameof(HelloCities));
        logger.LogInformation("Created new orchestration with instance ID = {instanceId}", instanceId);

        return client.CreateCheckStatusResponse(req, instanceId);
    }
}

Method Description
HelloCities Manages the durable orchestration. In this case, the orchestration starts, creates a list, and adds the result of three functions calls to the list. When the three function calls are complete, it returns the list.
SayHello The function returns a hello. It's the function that contains the business logic that is being orchestrated.
StartHelloCities An HTTP-triggered function that starts an instance of the orchestration and returns a check status response.

Test the function locally

Azure Functions Core Tools lets you run an Azure Functions project on your local development computer. You're prompted to install these tools the first time you start a function from Visual Studio.

  1. To test your function, press F5. If prompted, accept the request from Visual Studio to download and install Azure Functions Core (CLI) tools. You may also need to enable a firewall exception so that the tools can handle HTTP requests.

  2. Copy the URL of your function from the Azure Functions runtime output.

    Screenshot of Azure local runtime.

  3. Paste the URL for the HTTP request into your browser's address bar and execute the request. The following shows the response in the browser to the local GET request returned by the function:

    Screenshot of the browser window with statusQueryGetUri called out.

    The response is the HTTP function's initial result, letting us know that the durable orchestration has started successfully. It isn't yet the end result of the orchestration. The response includes a few useful URLs. For now, let's query the status of the orchestration.

  4. Copy the URL value for statusQueryGetUri, paste it into the browser's address bar, and execute the request.

    The request will query the orchestration instance for the status. You must get an eventual response that looks like the following. This output shows us the instance has completed and includes the outputs or results of the durable function.

    {
        "name":"HelloCities",
        "instanceId":"668814ac6ce84a43a9e6757f81dbc0bc",
        "runtimeStatus":"Completed",
        "input":null,
        "customStatus":null,
        "output":"Hello, Tokyo! Hello, London! Hello Seattle!",
        "createdTime":"2023-01-31T16:44:34Z",
        "lastUpdatedTime":"2023-01-31T16:44:37Z"
    }
    
  5. To stop debugging, press Shift + F5.

After you've verified that the function runs correctly on your local computer, it's time to publish the project to Azure.

Publish the project to Azure

You must have a function app in your Azure subscription before publishing your project. You can create a function app right from Visual Studio.

  1. In Solution Explorer, right-click the project and select Publish. In Target, select Azure then Next.

    Screenshot of publish window.

  2. Select Azure Function App (Windows) for the Specific target, which creates a function app that runs on Windows, and then select Next.

    Screenshot of publish window with specific target.

  3. In the Function Instance, choose Create a new Azure Function...

    Screenshot of create a new function app instance.

  4. Create a new instance using the values specified in the following table:

    Setting Value Description
    Name Globally unique name Name that uniquely identifies your new function app. Accept this name or enter a new name. Valid characters are: a-z, 0-9, and -.
    Subscription Your subscription The Azure subscription to use. Accept this subscription or select a new one from the drop-down list.
    Resource group Name of your resource group The resource group in which you want to create your function app. Select New to create a new resource group. You can also choose an existing resource group from the drop-down list.
    Plan Type Consumption When you publish your project to a function app that runs in a Consumption plan, you pay only for executions of your functions app. Other hosting plans incur higher costs.
    Location Location of the app service Choose a Location in a region near you or other services your functions access.
    Azure Storage General-purpose storage account An Azure storage account is required by the Functions runtime. Select New to configure a general-purpose storage account. You can also choose an existing account that meets the storage account requirements.
    Application Insights Application Insights instance You should enable Application Insights integration for your function app. Select New to create a new instance, either in a new or in an existing Log Analytics workspace. You can also choose an existing instance.

    Screenshot of Create App Service dialog.

  5. Select Create to create a function app and its related resources in Azure. The status of resource creation is shown in the lower-left of the window.

  6. In the Functions instance, make sure that the Run from package file is checked. Your function app is deployed using Zip Deploy with Run-From-Package mode enabled. Zip Deploy is the recommended deployment method for your functions project resulting in better performance.

    Screenshot of Finish profile creation.

  7. Select Finish, and on the Publish page, select Publish to deploy the package containing your project files to your new function app in Azure.

    After the deployment completes, the root URL of the function app in Azure is shown in the Publish tab.

  8. In the Publish tab, in the Hosting section, choose Open in Azure portal. This opens the new function app Azure resource in the Azure portal.

    Screenshot of Publish success message.

Test your function in Azure

  1. Copy the base URL of the function app from the Publish profile page. Replace the localhost:port portion of the URL you used when testing the function locally with the new base URL.

    The URL that calls your durable function HTTP trigger must be in the following format:

    https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>_HttpStart

  2. Paste this new URL for the HTTP request into your browser's address bar. You must get the same status response as before when using the published app.

Next steps

You have used Visual Studio to create and publish a C# Durable Functions app.