Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Quickstart: Create a C# Durable Functions app

Use Durable Functions, a feature of Azure Functions, to write stateful serverless workflows in C#. In this quickstart, you clone and run a sample app that demonstrates the function chaining orchestration pattern:

  • Function chaining: Calls activities sequentially (Tokyo → Seattle → London).

By the end, you'll have the orchestration running locally with the Durable Task Scheduler emulator and be able to view its status in the dashboard.

  • Clone and prepare the Hello Cities sample project.
  • Set up the Durable Task Scheduler emulator and Azurite for local development.
  • Build and run the function app and trigger the orchestration.
  • Review orchestration status and output in the Durable Task Scheduler dashboard.

Prerequisites

Set up the Durable Task Scheduler emulator

The Durable Task Scheduler emulator provides a local development environment so you can test orchestrations without an Azure subscription. The .NET Functions host also requires Azurite for local storage.

Start both containers:

docker run -d --name dtsemulator -p 8080:8080 -p 8082:8082 \
 mcr.microsoft.com/dts/dts-emulator:latest

docker run -d --name azurite -p 10000:10000 -p 10001:10001 -p 10002:10002 \
 mcr.microsoft.com/azure-storage/azurite

Tip

Once the emulator is running, you can access the Durable Task Scheduler dashboard at http://localhost:8082 to monitor orchestrations.

Run the quickstart sample

  1. Navigate to the Hello Cities sample directory:

    cd samples/durable-functions/dotnet/HelloCities/http
    
  2. Create a local.settings.json file with the emulator configuration:

    {
     "IsEncrypted": false,
     "Values": {
     "AzureWebJobsStorage": "UseDevelopmentStorage=true",
     "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
     "DURABLE_TASK_SERVICE_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None",
     "TASKHUB_NAME": "default"
     }
    }
    
  3. Build the project:

    dotnet build
    
  4. Start the function app:

    func start
    
  5. In a separate terminal, trigger the orchestration:

    $response = Invoke-RestMethod -Method POST -Uri http://localhost:7071/api/DurableFunctionsOrchestrationCSharp1_HttpStart
    $response
    

    The response contains status URLs for the orchestration instance. Copy the statusQueryGetUri value and run it to check the result:

    Invoke-RestMethod -Uri $response.statusQueryGetUri
    

Expected output

The POST request returns a JSON response with status URLs. For example:

{
 "id": "<instanceId>",
 "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/<instanceId>?code=...",
 "sendEventPostUri": "...",
 "terminatePostUri": "...",
 "purgeHistoryDeleteUri": "..."
}

When you query statusQueryGetUri and the orchestration's runtimeStatus is Completed, you can find the greeting results in the output field:

{
 "name": "DurableFunctionsOrchestrationCSharp1",
 "runtimeStatus": "Completed",
 "output": ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
}

Tip

If runtimeStatus shows Running or Pending, wait a moment and query the statusQueryGetUri again.

Open the Durable Task Scheduler dashboard at http://localhost:8082 to view the orchestration status and execution history.

Understand the code

The sample project in DurableFunctionsOrchestrationCSharp1.cs contains all three function types needed for a Durable Functions app.

Activity function

The SayHello activity takes a city name and returns a greeting:

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

Orchestrator function

The orchestrator calls SayHello sequentially for three cities:

[Function(nameof(DurableFunctionsOrchestrationCSharp1))]
public static async Task<List<string>> RunOrchestrator(
 [OrchestrationTrigger] TaskOrchestrationContext context)
{
 ILogger logger = context.CreateReplaySafeLogger(nameof(DurableFunctionsOrchestrationCSharp1));
 logger.LogInformation("Saying hello.");
 var outputs = new List<string>();

 outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Tokyo"));
 outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "Seattle"));
 outputs.Add(await context.CallActivityAsync<string>(nameof(SayHello), "London"));

 return outputs;
}

Client function

An HTTP-triggered client function starts the orchestration:

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

 logger.LogInformation("Started orchestration with ID = '{instanceId}'.", instanceId);
 return await client.CreateCheckStatusResponseAsync(req, instanceId);
}

Configuration

The sample uses the Durable Task Scheduler emulator as its storage backend. This is configured in host.json:

{
 "version": "2.0",
 "extensions": {
 "durableTask": {
 "storageProvider": {
 "type": "azureManaged",
 "connectionStringName": "DURABLE_TASK_SERVICE_CONNECTION_STRING"
 },
 "hubName": "%TASKHUB_NAME%"
 }
 }
}

The emulator connection string and task hub name are set in local.settings.json:

{
 "Values": {
 "AzureWebJobsStorage": "UseDevelopmentStorage=true",
 "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
 "DURABLE_TASK_SERVICE_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None",
 "TASKHUB_NAME": "default"
 }
}

Clean up resources

Stop the emulator containers when you're done:

docker stop dtsemulator azurite && docker rm dtsemulator azurite

Next steps


Feedback

Was this page helpful?

Additional resources