Temporalio 0.1.0-alpha1
See the version list below for details.
dotnet add package Temporalio --version 0.1.0-alpha1
NuGet\Install-Package Temporalio -Version 0.1.0-alpha1
<PackageReference Include="Temporalio" Version="0.1.0-alpha1" />
<PackageVersion Include="Temporalio" Version="0.1.0-alpha1" />
<PackageReference Include="Temporalio" />
paket add Temporalio --version 0.1.0-alpha1
#r "nuget: Temporalio, 0.1.0-alpha1"
#:package Temporalio@0.1.0-alpha1
#addin nuget:?package=Temporalio&version=0.1.0-alpha1&prerelease
#tool nuget:?package=Temporalio&version=0.1.0-alpha1&prerelease
Temporal .NET SDK
Temporal is a distributed, scalable, durable, and highly available orchestration engine used to execute asynchronous, long-running business logic in a scalable and resilient way.
"Temporal .NET SDK" is the framework for authoring workflows and activities using .NET programming languages.
Also see:
- NuGet Package
- Application Development Guide (TODO: .NET docs)
- API Documentation
- Samples (TODO)
⚠️ UNDER ACTIVE DEVELOPMENT
This SDK is under active development and has not released a stable version yet. APIs may change in incompatible ways until the SDK is marked stable.
Notably missing from this SDK:
- Activity workers
- Workflow workers
(for the previous .NET SDK repo, see https://github.com/temporalio/experiment-dotnet)
Quick Start
Installation
Add the Temporalio package from NuGet. For example, using the dotnet
CLI:
dotnet add package Temporalio --prerelease
NOTE: This README is for the current branch and not necessarily what's released on NuGet.
Usage
Workflow Definitions
The current SDK does not yet support workflows written in .NET, but workflows from other languages can still be defined in .NET to be properly typed.
Client
A client can be created an used to start a workflow. For example:
using Temporalio.Client;
// Create client connected to server at the given address and namespace
var client = await TemporalClient.ConnectAsync(new()
{
TargetHost = "localhost:7233",
Namespace = "my-namespace",
});
// Start a workflow
var handle = await client.StartWorkflowAsync(
IMyWorkflow.RunAsync,
"some workflow argument",
new() { ID = "my-workflow-id", TaskQueue = "my-workflow-queue" });
// Wait for a result
var result = await handle.GetResultAsync();
Console.WriteLine("Result: {0}", result);
Notes about the above code:
- Temporal clients are not explicitly disposable.
- To enable TLS, the
Tlsoption can be set to a non-nullTlsOptionsinstance. - Instead of
StartWorkflowAsync+GetResultAsyncabove, there is anExecuteWorkflowAsyncextension method that is clearer if the handle is not needed. - Non-typesafe forms of
StartWorkflowAsyncandExecuteWorkflowAsyncexist when there is no workflow definition or the workflow may take more than one argument or some other dynamic need. These simply take string workflow type names and an object array for arguments. - The
handleabove represents aWorkflowHandlewhich has specific workflow operations on it. For existing workflows, handles can be obtained viaclient.GetWorkflowHandle.
Data Conversion
Data converters are using to convert raw Temporal payloads to/from actual .NET types. A custom data converter can be set
via the DataConverter option when creating a client. Data converters are a combination of payload converters, payload
codecs, and failure converters. Payload converters convert .NET values to/from serialized bytes. Payload codecs convert
bytes to bytes (e.g. for compression or encryption). Failure converters convert exceptions to/from serialized failures.
Data converters are in the Temporalio.Converters namespace. The default data converter uses a default payload
converter, which supports the following types:
nullbyte[]Google.Protobuf.IMessageinstances- Anything that
System.Text.Jsonsupports
Custom converters can be created for all uses. Due to potential sandboxing use, payload converters must be specified as types not instances. For example, to create client with a data converter that converts all C# property names to camel case, you would:
using System.Text.Json;
using Temporalio.Client;
using Temporalio.Converters;
public class CamelCasePayloadConverter : DefaultPayloadConverter
{
public CamelCasePayloadConverter()
: base(new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })
{
}
}
var client = await TemporalClient.ConnectAsync(new()
{
TargetHost = "localhost:7233",
Namespace = "my-namespace",
DataConverter = DataConverter.Default with { PayloadConverterType = typeof(CamelCasePayloadConverter) },
});
Workflows
Workflows cannot yet be written in .NET but they can be defined.
Definition
Workflows are defined as classes or interfaces with a [Workflow] attribute. The entry point method for a workflow has
the [WorkflowRun] attribute. Methods for signals and queries have the [WorkflowSignal] and [WorkflowQuery]
attributes respectively. Here is an example of a workflow definition:
using System.Threading.Tasks;
using Temporalio.Workflow;
public record GreetingInfo(string Salutation = "Hello", string Name = "<unknown>");
[Workflow]
public interface IGreetingWorkflow
{
static readonly IGreetingWorkflow Ref = Refs<IGreetingWorkflow>.Instance;
[WorkflowRun]
public Task<string> RunAsync(GreetingInfo initialInfo);
[WorkflowSignal]
public Task UpdateSalutation(string salutation);
[WorkflowSignal]
public Task CompleteWithGreeting();
[WorkflowQuery]
public string CurrentGreeting();
}
Notes about the above code:
- The workflow client needs the ability to reference these instance methods, but C# doesn't allow referencing instance
methods without an instance. Therefore we add a readonly
Refinstance which is a proxy instance just for method references.- This is backed by a dynamic proxy generator but method invocations should never be made on it. It is only a for referencing methods.
- This is technically not needed. Any way that the method can be referenced for a client is acceptable.
- Source generators will provide an additional, alternative way to use workflows in a typed way in the future.
[Workflow]attribute must be present on the workflow type.- The attribute can have a string argument for the workflow type name. Otherwise the name is defaulted to the
unqualified type name (with the
Iprefix removed if on an interface and has a capital letter following).
- The attribute can have a string argument for the workflow type name. Otherwise the name is defaulted to the
unqualified type name (with the
[WorkflowRun]attribute must be present on one and only one public method.- The workflow run method must return a
Task. - The workflow run method should accept a single parameter and return a single type that are often srecord. Records are encouraged because optional fields can be added without affecting backwards compatibility of the workflow definition.
- The parameters of this method and its return type are considered the parameters and return type of the workflow itself.
- This attribute is not inherited and this method must be explicitly defined on the declared workflow type. Even if the method functionality should be inherited, for clarity reasons it must still be explicitly defined even if it just invokes the base class method.
- The workflow run method must return a
[WorkflowSignal]attribute may be present on any public method that handles signals.- Signal methods must return a
Task. - The attribute can have a string argument for the signal name. Otherwise the name is defaulted to the unqualified
method name with
Asynctrimmed off the end if it is present. - This attribute is not inherited and therefore must be explicitly set on any override.
- Signal methods must return a
[WorkflowQuery]attribute may be present on any public method that handles queries.- Query methods must be non-
voidbut cannot return aTask(i.e. they cannot be async). - The attribute can have a string argument for the query name. Otherwise the name is defaulted to the unqualified method name.
- This attribute is not inherited and therefore must be explicitly set on any override.
- Query methods must be non-
Activities
Activities are not implemented yet.
Development
Build
With dotnet installed with all needed frameworks and Rust installed (i.e.
cargo on the PATH), run:
dotnet build
Or for release:
dotnet build --configuration Release
Code formatting
This project uses StyleCop analyzers with some overrides in .editorconfig. To format, run:
dotnet format
Can also run with --verify-no-changes to ensure it is formatted.
VisualStudio Code
When developing in vscode, the following JSON settings will enable StyleCop analyzers in:
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableRoslynAnalyzers": true
Testing
Run:
dotnet test
Can add options like:
--logger "console;verbosity=detailed"to show logs- TODO(cretz): This doesn't show Rust stdout. How do I do that?
--filter "FullyQualifiedName=Temporalio.Tests.Client.TemporalClientTests.ConnectAsync_Connection_Succeeds"to run a specific test--blame-crashto do a host process dump on crash
To help debug native pieces, this is also available as an in-proc test program. Run:
dotnet run --project tests/Temporalio.Tests
Extra args can be added after --, e.g. -- --verbose would show verbose logs and -- --help would show other
options. If the arguments are anything but --help, the current assembly is prepended to the args before sending to the
xUnit runner.
Rebuilding Rust extension and interop layer
To regen core interop from header, install ClangSharpPInvokeGenerator like:
dotnet tool install --global ClangSharpPInvokeGenerator
Then, run:
ClangSharpPInvokeGenerator @src/Temporalio/Bridge/GenerateInterop.rsp
The Rust DLL is built automatically when the project is built. protoc may need to be on the PATH to build the Rust
DLL.
Regenerating protos
Must have protoc on the PATH. Note, for now you must use protoc 3.x until
our GH action downloader is fixed or we change how we download
protoc and check protos (since protobuf
changed some C# source).
Then:
dotnet run --project src/Temporalio.Api.Generator
Regenerating API docs
Install docfx, then run:
docfx src/Temporalio.ApiDoc/docfx.json
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 is compatible. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETCoreApp 3.1
- Castle.Core (>= 5.1.0)
- Google.Protobuf (>= 3.21.9)
- Microsoft.Extensions.Logging.Abstractions (>= 2.2.0)
-
.NETFramework 4.6.2
- Castle.Core (>= 5.1.0)
- Google.Protobuf (>= 3.21.9)
- Microsoft.Extensions.Logging.Abstractions (>= 1.1.1)
- System.Text.Json (>= 6.0.7)
-
.NETStandard 2.0
- Castle.Core (>= 5.1.0)
- Google.Protobuf (>= 3.21.9)
- Microsoft.Extensions.Logging.Abstractions (>= 2.2.0)
- System.Text.Json (>= 6.0.7)
NuGet packages (13)
Showing the top 5 NuGet packages that depend on Temporalio:
| Package | Downloads |
|---|---|
|
Temporalio.Extensions.Hosting
Temporal SDK .NET Hosting and Dependency Injection Extension |
|
|
Temporalio.Extensions.OpenTelemetry
Temporal SDK .NET OpenTelemetry Extension |
|
|
Temporalio.Extensions.DiagnosticSource
Temporal SDK .NET Diagnostic Source Extension |
|
|
XiansAi.Lib
This is a library for the Xians.Ai flow projects. This LIbrary is used by the Flows. It contains the base classes, interfaces and other utilities for creating and running Flows. |
|
|
Neon.Temporal
Useful classes and extensions for Temporal |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on Temporalio:
| Repository | Stars |
|---|---|
|
temporalio/samples-dotnet
Samples for working with the Temporal .NET SDK
|
| Version | Downloads | Last Updated |
|---|---|---|
| 1.10.0 | 58,752 | 1/13/2026 |
| 1.9.0 | 560,565 | 9/26/2025 |
| 1.8.0 | 348,531 | 9/2/2025 |
| 1.7.0 | 677,216 | 6/9/2025 |
| 1.6.0 | 307,378 | 4/21/2025 |
| 1.5.0 | 480,864 | 2/13/2025 |
| 1.4.0 | 176,431 | 12/19/2024 |
| 1.3.1 | 383,970 | 9/11/2024 |
| 1.3.0 | 111,035 | 8/14/2024 |
| 1.2.0 | 83,157 | 6/27/2024 |
| 1.1.2 | 42,843 | 6/5/2024 |
| 1.1.1 | 27,659 | 5/10/2024 |
| 1.1.0 | 4,228 | 5/7/2024 |
| 1.0.0 | 281,611 | 12/5/2023 |
| 0.1.0-beta2 | 29,265 | 10/30/2023 |
| 0.1.0-beta1 | 44,727 | 7/24/2023 |
| 0.1.0-alpha6 | 5,756 | 6/29/2023 |
| 0.1.0-alpha5 | 11,870 | 5/26/2023 |
| 0.1.0-alpha4 | 2,522 | 5/1/2023 |
| 0.1.0-alpha3 | 1,300 | 4/20/2023 |
| 0.1.0-alpha2 | 2,002 | 2/10/2023 |
| 0.1.0-alpha1 | 900 | 2/2/2023 |