.NET SDK technical resources and links
Available resources include: .NET API Documentation at https://dotnet.temporal.io/api/, .NET SDK Code Samples at https://github.com/temporalio/samples-dotnet, .NET SDK GitHub at https://github.com/temporalio/sdk-dotnet, Temporal 101 in .NET Free Course at https://learn.temporal.io/courses/temporal_101/dotnet/, Temporal .NET Community Slack, and .NET SDK Forum.
.NET SDK installation and quickstart
Detailed installation instructions for the .NET SDK are available in the Quickstart guide. A walkthrough covers how to use Temporal primitives (Activities, Workflows, and Workers) to build and run a Temporal application.
.NET SDK recommended learning path
After setting up a local Temporal Service, the recommended progression is: Workflow basics, Activity basics, Start an Activity execution, Run Worker processes. From there, developers can dive deeper into specific Temporal primitives.
.NET SDK documentation structure and topics
The .NET SDK developer guide covers: Workflow basics, Activity basics, Activity execution, Worker processes, Child Workflows, Continue-As-New, Cancellation, Timeouts, Message passing, Schedules, Timers, Dynamic Workflow, Versioning, Standalone Activities, Asynchronous Activity completion, Dynamic Activity, Benign exceptions, Worker Interceptors, Temporal Client, Temporal Nexus, Observability, Enriching the UI, Error handling, Testing, Debugging, and Converters and encryption.
Inbound Workflow Interceptor details
Inbound Workflow Interceptor wraps calls arriving into a Workflow Execution, such as executing the Workflow and handling Messages. It runs on Worker (Workflow sandbox). Example methods include ExecuteWorkflowAsync(), WorkflowHandle.QueryAsync(), WorkflowHandle.SignalAsync(), and WorkflowHandle.ExecuteUpdateAsync().
Outbound Workflow Interceptor details
Outbound Workflow Interceptor wraps calls a Workflow makes to the SDK, such as scheduling Activities, starting Child Workflows, and invoking Nexus Operations. It runs on Worker (Workflow sandbox). Example methods include StartActivityAsync(), StartChildWorkflowAsync(), ChildWorkflowHandle.SignalAsync(), and StartNexusOperationAsync().
Activity metrics interceptor example
Example showing how to implement a Worker Interceptor that measures Schedule-To-Start and Schedule-To-Close latency for activities. The SimpleWorkerInterceptor implements IWorkerInterceptor and returns an ActivityMetricsInterceptor that wraps ExecuteActivityAsync, recording latency before and after activity execution.
Interceptors overview in .NET SDK
Interceptors are SDK hooks that intercept inbound and outbound Temporal calls, allowing you to apply shared behavior across many calls such as tracing and authorization before calls reach application code and after they return. They work similarly to middleware in frameworks like ASP.NET Core.
Five categories of interceptors in .NET SDK
The five interceptor categories are: Outbound Client (wraps calls from application to Temporal Client to start a Workflow or send Messages), Inbound Workflow (wraps calls arriving into Workflow Execution), Outbound Workflow (wraps calls a Workflow makes to SDK), Inbound Activity (wraps calls arriving into Activity Execution), and Outbound Activity (wraps calls an Activity makes to SDK).
Outbound Client Interceptor details
Outbound Client Interceptor wraps calls from application to Temporal Client to start a Workflow or send Messages. It runs on the Client. Example methods include StartWorkflowAsync(), WorkflowHandle.SignalAsync(), and ListWorkflowsAsync().
Inbound Activity Interceptor details
Inbound Activity Interceptor wraps calls arriving into an Activity Execution. It runs on Worker (Activity context). Example method is ExecuteActivityAsync().
Outbound Activity Interceptor details
Outbound Activity Interceptor wraps calls an Activity makes to the SDK, such as sending Heartbeats and reading Activity info. It runs on Worker (Activity context). Example methods include Info() and Heartbeat().
Activity and Client interceptors are not affected by replay
Activity and Client interceptors do not execute during replay, so they are not constrained by replay-safe API requirements.
Register interceptor on Worker
To register an interceptor on the Worker only, pass interceptors in the Interceptors argument of TemporalWorkerOptions. Worker interceptors modify inbound and outbound Workflow and Activity calls.
Implement Client Interceptor interface
To modify outbound Client calls, define a class implementing IClientInterceptor. Implement InterceptClient() to return a ClientOutboundInterceptor, overriding the outbound Client calls you want to modify. IClientInterceptor.InterceptClient receives the next ClientOutboundInterceptor in the chain and returns the created interceptor.
Implement Worker Interceptor interface
To modify inbound Workflow and Activity calls, define a class implementing IWorkerInterceptor. It provides InterceptActivity(), InterceptWorkflow(), and InterceptNexusOperation() methods for Activity, Workflow, and Nexus interception respectively.
Interceptor methods need not implement every method
Interceptor classes do not need to implement every method. The default implementation is always to pass the data on to the next method in the interceptor chain.
Context propagation interceptor example
Example showing how to implement a Client Interceptor that sets a User ID in outbound headers. The ContextPropagationInterceptor implements IClientInterceptor and returns a ContextPropagationClientOutboundInterceptor that overrides StartWorkflowAsync to inject a user-id header from AsyncLocal context storage.
.NET SDK minimum version requirement
The .NET SDK requires .NET 6.0 or later.
Create .NET Temporal solution structure
Create three projects in a solution: Workflow (class library), Worker (console), and Client (console). Add project references so Worker and Client both reference Workflow. Install the Temporalio package in all three projects using 'dotnet add'. You can also centralize the Temporalio package for all projects using Directory.Packages.props and Directory.Build.props at the solution root.
.NET SDK Workflows documentation sections
The .NET SDK Workflows documentation covers the following topics: Workflow basics, Child Workflows, Continue-As-New, Cancellation, Timeouts, Message passing, Schedules, Timers, Dynamic Workflow, and Versioning.
BackfillAsync method executes scheduled actions ahead of time
Use the BackfillAsync() method on a ScheduleHandle to execute scheduled actions ahead of their specified time range. This is useful for executing missed or delayed actions or testing workflows before their scheduled time. Pass a collection of ScheduleBackfill objects with StartAt, EndAt, and Overlap properties.
BackfillAsync code example for backfilling a schedule 20-30 days ago
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = client.GetScheduleHandle("my-schedule-id");
var now = DateTime.Now;
await handle.BackfillAsync(new List<ScheduleBackfill>
{
new(
StartAt: now - TimeSpan.FromDays(30),
EndAt: now - TimeSpan.FromDays(20),
Overlap: ScheduleOverlapPolicy.AllowAll),
});
```
This example backfills a schedule to run for a period 30 to 20 days in the past.
DeleteAsync method deletes a schedule
Use the DeleteAsync() method on a ScheduleHandle to delete a schedule. Deleting a schedule does not affect any workflows that were already started by the schedule.
DeleteAsync code example
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = client.GetScheduleHandle("my-schedule-id");
await handle.DeleteAsync();
```
This example deletes a schedule using its handle.
DescribeAsync method gets schedule configuration and workflow run details
Use the DescribeAsync() method on a ScheduleHandle to retrieve detailed information about the current schedule configuration, including information about past, current, and future workflow runs.
DescribeAsync code example
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = client.GetScheduleHandle("my-schedule-id");
var desc = await handle.DescribeAsync();
Console.WriteLine("Schedule info: {0}", desc.Info);
```
This example retrieves and displays schedule information.
ListSchedulesAsync method returns async enumerable of all schedules
Use the ListSchedulesAsync() method on the TemporalClient to list all available schedules. This returns an async enumerable. If a schedule is added or deleted, it may not be available in the list immediately.
ListSchedulesAsync code example
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
await foreach (var desc in client.ListSchedulesAsync())
{
Console.WriteLine("Schedule info: {0}", desc.Info);
}
```
This example iterates through all available schedules and prints their information.
PauseAsync method pauses or unpauses a schedule
Use the PauseAsync() method on a ScheduleHandle to pause and unpause a schedule. When a schedule is paused, all future workflow runs associated with it are temporarily stopped. The method accepts an optional note string parameter to provide a reason for pausing.
PauseAsync code example
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = client.GetScheduleHandle("my-schedule-id");
await handle.PauseAsync("Pausing the schedule for now");
```
This example pauses a schedule with a note explaining the reason.
TriggerAsync method executes a schedule immediately
Use the TriggerAsync() method on a ScheduleHandle to trigger an immediate action with a given schedule. By default, this action is subject to the schedule's Overlap Policy.
TriggerAsync code example
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = client.GetScheduleHandle("my-schedule-id");
await handle.TriggerAsync();
```
This example triggers an immediate execution of a scheduled workflow.
UpdateAsync method modifies an existing schedule
Use the UpdateAsync() method on a ScheduleHandle to update an existing schedule's configuration such as start time, end time, or interval. The method accepts a callback function that receives ScheduleUpdateInput with the current schedule and returns a ScheduleUpdate with the modified schedule.
StartDelay code example with 3-hour delay
```csharp
var handle = await client.StartWorkflowAsync(
(MyWorkflow wf) => wf.RunAsync(),
new(id: "my-workflow-id", taskQueue: "my-task-queue")
{
StartDelay = TimeSpan.FromHours(3),
});
```
This example starts a workflow with a 3-hour delay before execution.
UpdateAsync code example for changing schedule action
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = client.GetScheduleHandle("my-schedule-id");
await handle.UpdateAsync(input =>
{
var newAction = ScheduleActionStartWorkflow.Create(
(MyWorkflow wf) => wf.RunAsync(),
new(id: "my-workflow-id", taskQueue: "my-task-queue"));
return new(input.Description.Schedule with { Action = newAction });
});
```
This example updates a schedule to use a new workflow action.
CreateScheduleAsync method creates a scheduled workflow in .NET
Use the CreateScheduleAsync method on the TemporalClient to create a scheduled workflow. Pass a Schedule ID string and a Schedule object with an Action property set to ScheduleActionStartWorkflow.Create() specifying the workflow method, workflow ID, and task queue. Include a Spec property with ScheduleIntervalSpec to define the schedule intervals.
CreateScheduleAsync code example for scheduling a workflow every 5 days
```csharp
using Temporalio.Client;
using Temporalio.Client.Schedules;
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
var handle = await client.CreateScheduleAsync(
"my-schedule-id",
new(
Action: ScheduleActionStartWorkflow.Create(
(MyWorkflow wf) => wf.RunAsync(),
new(id: "my-workflow-id", taskQueue: "my-task-queue")),
Spec: new()
{
Intervals = new List<ScheduleIntervalSpec> { new(Every: TimeSpan.FromDays(5)) },
}));
```
This example creates a schedule that triggers a workflow every 5 days.