Skip to content

feat: Implement Dapr.StateManagement package#1806

Merged
WhitWaldo merged 23 commits into
masterfrom
copilot/implement-dapr-statemangement
May 19, 2026
Merged

feat: Implement Dapr.StateManagement package#1806
WhitWaldo merged 23 commits into
masterfrom
copilot/implement-dapr-statemangement

Conversation

Copilot AI commented May 6, 2026

Copy link
Copy Markdown
Contributor
  • Implement Dapr.StateManagement package and source generator
  • Add serialization compatibility tests (inheritance, enums, primitives, complex)
  • Update DaprStateManagementGrpcClient to accept IDaprRuntimeCapabilities
  • Resolve merge conflicts with master
  • Apply factory-delegate AddDaprClient pattern uniformly to Jobs, Cryptography, AI, DistributedLock, Messaging, and SecretsManagement
  • Remove the now-unused reflection-based AddDaprClient overload
  • Verify all affected projects build and tests pass (74 Common, 174 Jobs, 81 Cryptography, 156 AI, 55 DistributedLock, 65 Messaging, 39 SecretsManagement, 54 StateManagement)
  • Validation passed (Code Review + CodeQL)

Copilot AI and others added 2 commits May 8, 2026 18:21
…, generic Serialize<T> overload

Agent-Logs-Url: https://github.com/dapr/dotnet-sdk/sessions/63945548-1b45-4e00-8494-4af62136db8b

Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>
@codecov

codecov Bot commented May 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 31.36792% with 291 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.46%. Comparing base (d708be4) to head (8474481).

Files with missing lines Patch % Lines
...anagement.Runtime/DaprStateManagementGrpcClient.cs 11.53% 274 Missing and 2 partials ⚠️
...ateManagement.Abstractions/Models/BulkStateItem.cs 0.00% 6 Missing ⚠️
...tateManagement.Abstractions/StateStoreAttribute.cs 0.00% 6 Missing ⚠️
...rc/Dapr.Common/Serialization/JsonDaprSerializer.cs 0.00% 0 Missing and 1 partial ⚠️
...nagement.Abstractions/DaprStateManagementClient.cs 83.33% 1 Missing ⚠️
.../DaprStateManagementServiceCollectionExtensions.cs 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1806      +/-   ##
==========================================
- Coverage   65.01%   63.46%   -1.55%     
==========================================
  Files         300      312      +12     
  Lines        8874     9279     +405     
  Branches     1043     1101      +58     
==========================================
+ Hits         5769     5889     +120     
- Misses       2848     3130     +282     
- Partials      257      260       +3     
Flag Coverage Δ
net10.0 63.45% <31.36%> (-1.55%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@WhitWaldo

Copy link
Copy Markdown
Contributor

@copilot This project is failing to build. Can you give it another pass?

…use new AddDaprClient<> factory delegates

Agent-Logs-Url: https://github.com/dapr/dotnet-sdk/sessions/4e81dcdf-2201-490f-9729-b9ae4477ab19

Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>

Copilot AI commented May 9, 2026

Copy link
Copy Markdown
Contributor Author

@copilot This project is failing to build. Can you give it another pass?

Fixed in 9ab98d1. Two root causes:

  1. DaprClientBuilderExtensionsTests — The 4 test call sites still used the old AddDaprClient<> signature (no factory delegates). Updated all 4 to pass config => new DaprTestClientBuilder(config) and svc => new DaprTestBuilder(svc). Also fixed DaprTestClientBuilder.Build() which was throwing NotImplementedException — it now calls BuildDaprClientDependencies and returns a real DaprTestGrpcClient.

  2. Dapr.Workflow.Test stub serializers — Adding Serialize<T>(T) to IDaprSerializer broke 6 stub/mock implementations (StubSerializer, CapturingSerializer, StubDaprSerializer, StubWorkflowSerializer, DependencyBasedSerializer, MockSerializer). Added the missing method to each.

Full solution now builds cleanly; 74 Dapr.Common.Test + 367 Dapr.Workflow.Test pass.

Copilot AI changed the title feat: implement Dapr.StateManagement package feat: implement Dapr.StateManagement package — AOT-safe, reflection-free May 9, 2026
@WhitWaldo WhitWaldo changed the title feat: implement Dapr.StateManagement package — AOT-safe, reflection-free feat: implement Dapr.StateManagement package May 12, 2026
@WhitWaldo WhitWaldo changed the title feat: implement Dapr.StateManagement package feat: Implement Dapr.StateManagement package May 12, 2026
@WhitWaldo

Copy link
Copy Markdown
Contributor

@copilot Could you please contrast this implementation, including the IDaprSerializer functionality, against what's currently available via the Dapr.Client package to get and set state? I need to ensure that there are no breaking changes such that if a user has written data via the DaprClient in the past and then reads it out via this package, it's going to properly serialize. Both approaches should be using System.Text.Json, but please ensure that there are no other impactful differences that might lead to a negative experience here.

Copilot AI commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Could you please contrast this implementation, including the IDaprSerializer functionality, against what's currently available via the Dapr.Client package to get and set state? I need to en...

Good question — here's a complete comparison of the two serialization paths.


Wire format (bytes on disk)

Both clients send/receive UTF-8 encoded JSON in the gRPC ByteString value field:

Old DaprClient New DaprStateManagementClient
Write JsonSerializer.SerializeToUtf8Bytes<T>(value, options) → raw UTF-8 bytes directly JsonSerializer.Serialize<T>(value, options) → JSON string → ByteString.CopyFromUtf8(json) → same UTF-8 bytes
Read JsonSerializer.Deserialize<T>(bytes.Span, options) response.Data.ToStringUtf8()JsonSerializer.Deserialize<T>(string, options)

The on-wire representation is identical — both produce the same UTF-8 JSON bytes. Data written by one client can be read correctly by the other.


JSON serializer options (the critical part)

Both builders inherit from DaprGenericClientBuilder<T>, which sets the default options as:

this.JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);

JsonSerializerDefaults.Web sets:

  • PropertyNamingPolicy = JsonNamingPolicy.CamelCase
  • PropertyNameCaseInsensitive = true
  • NumberHandling = JsonNumberHandling.AllowReadingFromString

The DaprStateManagementClientBuilder.Build() passes these same builder options directly to JsonDaprSerializer:

new JsonDaprSerializer(this.JsonSerializerOptions)  // same Web defaults, same as DaprClientBuilder

So the effective defaults at the builder/DI level are identical to DaprClient. (JsonDaprSerializer's default no-arg constructor adds IncludeFields = true as a convenience for direct instantiation, but that path is never taken by the builder — it always uses the options from DaprGenericClientBuilder.)


One small difference: null value handling

Old DaprClient New DaprStateManagementClient
Save null Stores JSON null bytes Stores empty ByteString (skips the value)
Load empty/null Returns default(T) Returns default(T)

Both produce the same logical result (default(T)) on read regardless of which side wrote the null. No user-visible difference.


Conclusion: There are no breaking changes. Data written by DaprClient will deserialize correctly with DaprStateManagementClient and vice versa — the wire format, encoding, JSON property naming, and case sensitivity are all identical by default.

Copilot AI commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot I'm seeing quite a few build errors. While I don't think they're directly related to this PR, can you please fix them anyway?

Fixed in f897218. DaprSecretsManagementServiceCollectionExtensions.AddDaprSecretsManagementClient() was calling AddDaprClient<> with the old (configure, lifetime) argument pattern, but our updated signature now requires the factory delegates as the first two positional parameters. Added config => new DaprSecretsManagementClientBuilder(config) and svc => new DaprSecretsManagementBuilder(svc) to match the same pattern used in all other SDK callers. Full solution now builds cleanly; all 74 Dapr.Common.Test + 54 Dapr.StateManagement.Test tests pass.

@WhitWaldo WhitWaldo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One follow-up question about the implementation

/// <returns>The <typeparamref name="TServiceBuilder"/> that wraps the service collection for further configuration.</returns>
internal static TServiceBuilder AddDaprClient<TClient, TConcreteClient, TServiceBuilder, TClientBuilder>(
this IServiceCollection services,
Func<IConfiguration?, TClientBuilder> clientBuilderFactory,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned that adding this here means that every single client using this method is going to have to be updated accordingly. Is this strictly necessary or can it be added as an overload?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 775b1f6. The original AddDaprClient overload (using reflection) has been restored alongside the new factory-delegate overload. Jobs, AI, Cryptography, DistributedLock, Messaging, and SecretsManagement all revert to the simpler (configure, lifetime) signature — no factory delegates required. Only the new StateManagement package uses the factory-delegate overload.

…nagement callers to simple signature

Agent-Logs-Url: https://github.com/dapr/dotnet-sdk/sessions/f4eda1e6-677a-4751-aeaa-098514c593ef

Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>
@WhitWaldo WhitWaldo merged commit 042b795 into master May 19, 2026
1138 of 1150 checks passed
@WhitWaldo WhitWaldo deleted the copilot/implement-dapr-statemangement branch May 19, 2026 19:45
@nelson-parente nelson-parente added this to the v1.18 milestone May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants