This skill should be used when the user asks to 'create a Temporal workflow in C#', 'write a .NET activity', 'use Temporalio', 'fix .NET workflow determinism', 'debug workflow replay', '.NET workflow logging', or mentions 'Temporal .NET SDK' or 'Temporal C#'. Provides .NET-specific patterns, CRITICAL Task scheduling guidance, and observability patterns.
The Temporal .NET SDK provides strongly-typed async/await workflows for .NET applications.
CRITICAL: Workflows use a custom TaskScheduler. Many standard Task patterns break determinism.
Understanding how Temporal achieves durable execution is essential for writing correct workflows.
When a Worker executes workflow code, it creates Commands (requests for operations like starting an Activity or Timer) and sends them to the Temporal Cluster. The Cluster maintains an Event History - a durable log of everything that happened during the workflow execution.
Key insight: During replay, the Worker re-executes your workflow code but uses the Event History to restore state instead of re-executing Activities. When it encounters an Activity call that has a corresponding event in history, it returns the stored result instead of scheduling a new execution.
ActivityTaskCompletedThis is why determinism matters: The Worker validates that Commands generated during replay match the Events in history. A mismatch causes a non-deterministic error because the Worker cannot reliably restore state.
.NET SDK has no sandbox - you must ensure determinism through code review and using the safe alternatives documented below. The custom TaskScheduler helps enforce some constraints but cannot catch all non-deterministic code.
// Activity
public class GreetingActivities
{
[Activity]
public string Greet(string name) => $"Hello, {name}!";
}
// Workflow
[Workflow]
public class GreetingWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string name)
{
return await Workflow.ExecuteActivityAsync(
(GreetingActivities act) => act.Greet(name),
new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });
}
}
// Worker
var client = await TemporalClient.ConnectAsync(new("localhost:7233"));
using var worker = new TemporalWorker(
client,
new TemporalWorkerOptions("greeting-queue")
.AddWorkflow<GreetingWorkflow>()
.AddAllActivities(new GreetingActivities()));
await worker.ExecuteAsync(cancellationToken);
[Workflow] attribute on class[WorkflowRun] on entry method[WorkflowSignal], [WorkflowQuery] for handlers[Activity] attribute on methodsActivityExecutionContext.Current for context.NET workflows use a custom TaskScheduler. Standard Task patterns break determinism.
DO NOT USE:
Task.Run() - uses default schedulerConfigureAwait(false) - bypasses contextTask.Delay() - uses system timerTask.WhenAny/WhenAll() - use Workflow versionsUSE INSTEAD:
Workflow.RunTaskAsync()Workflow.DelayAsync()Workflow.WhenAnyAsync/WhenAllAsync()See references/determinism.md for detailed rules.
Use Workflow.Logger inside Workflows for replay-safe logging that avoids duplicate messages:
[Workflow]
public class MyWorkflow
{
[WorkflowRun]
public async Task<string> RunAsync(string input)
{
// These logs are automatically suppressed during replay
Workflow.Logger.LogInformation("Workflow started with input: {Input}", input);
var result = await Workflow.ExecuteActivityAsync(
(MyActivities a) => a.Process(input),
new() { StartToCloseTimeout = TimeSpan.FromMinutes(5) });
Workflow.Logger.LogInformation("Workflow completed with result: {Result}", result);
return result;
}
}
For activities, use standard ILogger injection or ActivityExecutionContext.Logger:
public class MyActivities
{
[Activity]
public string Process(string input)
{
var logger = ActivityExecutionContext.Current.Logger;
logger.LogInformation("Processing: {Input}", input);
return $"Processed: {input}";
}
}
Task.Run() - Use Workflow.RunTaskAsync() insteadConfigureAwait(false) - Don't use in workflowsTask.Delay() - Use Workflow.DelayAsync() insteadTask.WhenAny/All - Use Workflow.WhenAny/AllAsync()Temporalio.Workflows.SemaphoreConsole.WriteLine() in workflows - Use Workflow.Logger insteadreferences/determinism.md - CRITICAL Task gotchas, history replay, safe alternativesreferences/error-handling.md - ApplicationFailureException, retry policies, idempotency patternsreferences/testing.md - WorkflowEnvironment, time-skipping, replay testingreferences/patterns.md - Signals, queries, DI integrationreferences/observability.md - OpenTelemetry tracing, replay-aware logging, metricsreferences/advanced-features.md - Updates, interceptors, search attributes, schedulesreferences/data-handling.md - Data converters, encryption, payload codecsreferences/versioning.md - Patching API, workflow type versioning, Worker Versioning