diff --git a/.editorconfig b/.editorconfig
index 5068e98..14835a8 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -98,6 +98,7 @@ dotnet_diagnostic.SA1513.severity = none
dotnet_diagnostic.SA1515.severity = none
# Do not require XML doc in samples
+dotnet_diagnostic.CS1591.severity = none
dotnet_diagnostic.SA1600.severity = none
dotnet_diagnostic.SA1602.severity = none
diff --git a/.gitignore b/.gitignore
index 97a330f..7ee9b6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ obj/
/.vs
/.vscode
/.idea
+.claude/
diff --git a/Directory.Build.props b/Directory.Build.props
index 772f1fd..95c3854 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,10 +5,8 @@
Temporal
true
true
-
+ true
enable
enable
MIT
diff --git a/src/ContextPropagation/ContextPropagationInterceptor.cs b/src/ContextPropagation/ContextPropagationInterceptor.cs
index 4292b66..784070d 100644
--- a/src/ContextPropagation/ContextPropagationInterceptor.cs
+++ b/src/ContextPropagation/ContextPropagationInterceptor.cs
@@ -1,6 +1,7 @@
namespace TemporalioSamples.ContextPropagation;
using System.Threading.Tasks;
+using NexusRpc.Handlers;
using Temporalio.Api.Common.V1;
using Temporalio.Client;
using Temporalio.Client.Interceptors;
@@ -39,6 +40,10 @@ public WorkflowInboundInterceptor InterceptWorkflow(WorkflowInboundInterceptor n
public ActivityInboundInterceptor InterceptActivity(ActivityInboundInterceptor nextInterceptor) =>
new ContextPropagationActivityInboundInterceptor(this, nextInterceptor);
+ public NexusOperationInboundInterceptor InterceptNexusOperation(
+ NexusOperationInboundInterceptor nextInterceptor) =>
+ new ContextPropagationNexusOperationInboundInterceptor(this, nextInterceptor);
+
private Dictionary HeaderFromContext(IDictionary? existing)
{
var ret = existing != null ?
@@ -67,6 +72,28 @@ private TResult WithHeadersApplied(
return func();
}
+ private Dictionary HeaderFromContextForNexus(IDictionary? existing)
+ {
+ var ret = existing != null ?
+ new Dictionary(existing) : new Dictionary(1);
+ // Nexus headers are string-based, so serialize context value to JSON.
+ // Alternative approach: could use payload converter and put entire payload as JSON on header.
+ ret[headerKey] = System.Text.Json.JsonSerializer.Serialize(context.Value);
+ return ret;
+ }
+
+ private Task WithHeadersAppliedForNexusAsync(
+ IReadOnlyDictionary? headers, Func> func)
+ {
+ if (headers?.TryGetValue(headerKey, out var value) == true)
+ {
+ // Deserialize can return null for nullable types, which is expected
+ context.Value = System.Text.Json.JsonSerializer.Deserialize(value)!;
+ }
+ // These are async local, no need to unapply afterwards
+ return func();
+ }
+
private class ContextPropagationClientOutboundInterceptor : ClientOutboundInterceptor
{
private readonly ContextPropagationInterceptor root;
@@ -153,6 +180,11 @@ public override Task> StartChildWorkflow
StartChildWorkflowInput input) =>
Next.StartChildWorkflowAsync(
input with { Headers = root.HeaderFromContext(input.Headers) });
+
+ public override Task> StartNexusOperationAsync(
+ StartNexusOperationInput input) =>
+ Next.StartNexusOperationAsync(
+ input with { Headers = root.HeaderFromContextForNexus(input.Headers) });
}
private class ContextPropagationActivityInboundInterceptor : ActivityInboundInterceptor
@@ -166,4 +198,19 @@ public ContextPropagationActivityInboundInterceptor(
public override Task