Skip to content

feat!: target net9.0 and net10.0 with configurable frameworks - #151

Merged
JacobAtchley merged 7 commits into
mainfrom
forks/jatchley/dotnet10-multitarget
Oct 8, 2026
Merged

JacobAtchley merged 7 commits into
mainfrom
forks/jatchley/dotnet10-multitarget

Conversation

@JacobAtchley

@JacobAtchley JacobAtchley commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Target frameworks come from FirebendTargetFrameworks in Directory.Build.props (currently net9.0;net10.0). Samples and other runnable apps use FirebendAppTargetFramework (net10.0). Adding .NET 11 later means editing that list and adding one net11.0 block to Directory.Packages.props.
  • Package versions move to central package management in Directory.Packages.props. Microsoft framework packages are versioned per framework: 9.0.x for net9.0 and 10.0.x for net10.0. Other packages are updated to their latest stable versions.
  • A repo nuget.config restricts restore to nuget.org.
  • global.json pins SDK 10.0.401 with rollForward: latestPatch, so local builds and CI run the same analyzer rules. CI reads it through actions/setup-dotnet@v4 (global-json-file) and also installs the 9.0 SDK for the net9.0 test runtime. CI uses actions/checkout@v4.
  • The release workflow sets up .NET before installing Versionize, so the tool installs on the pinned SDK.
  • Dependabot opens monthly dotnet-sdk updates for global.json.
  • Packages now embed the icon and use PackageLicenseExpression (MIT) instead of the deprecated PackageIconUrl and PackageLicenseUrl (NU5048, NU5125).
  • FluentAssertions is pinned to 7.x, because v8 requires a commercial license.
  • The first commit is feat!: with a BREAKING CHANGE: footer, so Versionize will release a new major version.

lit-redis specifics

  • Next version: 5.0.0 → 6.0.0.
  • The netstandard2.1 target is dropped.
  • StackExchange.Redis 2.9.11 → 3.3.1. StringSetAsync now takes an Expiration. Consumers who reference StackExchange.Redis directly must move to 3.x. On net9.0, StackExchange.Redis 3.x pulls in Microsoft.Extensions.Logging.Abstractions 10.0.5. I checked that the 47 StackExchange.Redis references in Microsoft.Extensions.Caching.StackExchangeRedis all still resolve against 3.3.1.
  • Removed references the framework now provides: System.Text.Json and System.ComponentModel.TypeConverter.
  • Interface members carry an explicit public, as the .NET 10 SDK's IDE0040 rule requires. The .editorconfig rule is unchanged.

Test plan

  • dotnet build -c Release: 0 warnings, 0 errors (SDK 10.0.401)
  • dotnet format --verify-no-changes passes
  • Unit tests: 13/13 on net9.0 and 13/13 on net10.0
  • Ran LitRedis.Sample against a local Redis 7 container: caching, the distributed cache, and locking all worked
  • The package contains lib/net9.0 and lib/net10.0, the embedded icon, and the MIT license expression

🤖 Generated with Claude Code

https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98

JacobAtchley and others added 5 commits October 7, 2026 13:24
Directory.Build.props defines FirebendTargetFrameworks (net9.0;net10.0)
for the library and tests and FirebendAppTargetFramework (net10.0) for the
sample. Central package management in Directory.Packages.props gives the
Microsoft.Extensions.* packages per-framework versions (9.0.x for net9.0,
10.0.x for net10.0). Packages are updated, including StackExchange.Redis
2.9.11 to 3.3.1, and in-box System.Text.Json and
System.ComponentModel.TypeConverter references are removed. CI installs
the 9 and 10 SDKs.

BREAKING CHANGE: packages now target only net9.0 and net10.0; the
netstandard2.1 target is dropped. StackExchange.Redis is now 3.x, so
consumers must be on StackExchange.Redis 3.x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98
FluentAssertions 8 requires a commercial license.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98
Restores the always rule for dotnet_style_require_accessibility_modifiers and
adds the explicit public modifiers the .NET 10 SDK now flags (IDE0040).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98
Replaces the deprecated PackageLicenseUrl and PackageIconUrl (NU5125, NU5048)
with PackageLicenseExpression and an embedded nuget-image.png, packed from
Directory.Build.props for every project that sets PackageIcon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98
global.json pins SDK 10.0.401 with rollForward latestPatch, so local builds and
CI run the same analyzer rules and a new SDK feature band can no longer break
dotnet format without a code change. CI reads global.json through setup-dotnet
and still installs the 9.0 SDK for the net9.0 test runtime. The release workflow
now sets up .NET before installing Versionize, so the dotnet tool install runs
on the pinned SDK. Dependabot opens monthly dotnet-sdk updates for global.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98

@mcarey1590 mcarey1590 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.

Reviewed the full diff. Nothing blocking; leaning approve. CI green (not built locally).

Worth addressing

  • StackExchange.Redis goes 2.x → 3.x. Unit tests pass on net9.0 (13), but the live-Redis manual run only used the net10.0 sample, so the net9.0 build against a real Redis is untested. Consider a net9 integration run before release.
  • LitRedisCacheStore.cs:52: expiry.HasValue ? new Expiration(expiry.Value) : Expiration.Default. Please confirm null expiry still means "no TTL" under SE.Redis 3; a small test asserting that would settle it.

Low / info

  • Per-TFM PackageVersion blocks in Directory.Packages.props: a new TFM with no block fails with NU1010 (loud, fine), but Dependabot may handle the conditional blocks unevenly.
  • Version goes 5.0.0 → 6.0.0 via Versionize. If squash-merged, the title must keep ! and the BREAKING CHANGE: footer or it cuts a minor.
  • netstandard2.1 dropped, so net8 consumers can't take this. Worth confirming that's intended and calling it out in release notes.

Ordering: should release before jobba#214 (jobba pins LitRedis.Core 5.0.0). Dependents must move to SE.Redis 3.x together; mixing 2.x and 3.x in one graph will fail.

JacobAtchley and others added 2 commits October 7, 2026 16:15
Adds a Building from source section covering global.json and the
FirebendTargetFrameworks and FirebendAppTargetFramework properties. Dependabot
now ignores major updates to the framework-aligned Microsoft packages, which
are versioned per target framework in Directory.Packages.props.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98
Pin that a null expiry maps to Expiration.Default (a plain SET that
clears any existing TTL, matching the 2.x expiry: null behavior) and
not Expiration.KeepTtl, and that a set expiry maps to a relative
Expiration of the same span.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMzvDp6hZ4dnMSGobxdo98
@JacobAtchley

Copy link
Copy Markdown
Collaborator Author

Responses to the review:

  • Expiration.Default with a null expiry: it still means no TTL. It does not mean KEEPTTL.
    • In SE.Redis 3.3.1, Expiration.Default is "no expiration" for writes and renders as a bare SET. Expiration.KeepTtl is a separate value.
    • I checked against a live Redis 7 through LitRedisCacheStore on both net9.0 and net10.0. A put with a 5m expiry gives TTL 300, and overwriting with a null expiry gives TTL -1.
    • A small SE.Redis 2.9.11 app shows the same result (TTL 300, then -1), so behavior is unchanged from 2.x.
    • New unit tests check the exact Expiration passed for a null and a non-null expiry. The null case asserts it is not KeepTtl, and that test fails if the code is switched to KeepTtl.
  • net9.0 against a real Redis: done. I built LitRedis.Sample with -p:FirebendAppTargetFramework=net9.0. It resolves StackExchange.Redis 3.3.1 alongside Microsoft.Extensions.Caching.StackExchangeRedis 9.0.20. Against redis:7-alpine, caching, the distributed cache and every lock example behaved as on net10.0, with no MissingMethodException.
  • Dependabot: now ignores major updates to the framework-aligned Microsoft packages, so it won't move the 9.0.x block to 10.x.
  • README: added a "Building from source" section covering global.json and the framework properties.
  • Squash merge: the PR title keeps feat!:, and the repo's squash message includes the commit messages, so the BREAKING CHANGE: footer is carried into the squash commit too.
  • Dropping netstandard2.1: intended, and it's in the breaking-change footer for the 6.0.0 changelog.
  • Ordering: agreed. Release this before jobba#214, and jobba moves to LitRedis.Core 6.0.0 and SE.Redis 3.x together.

@mcarey1590 mcarey1590 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.

Verified the follow-ups: null-expiry tests added (LitRedisCacheStoreTests), net9.0 sample run against Redis 7 reported, README and Dependabot ignore added, CI green. Approving. Release this before jobba#214 moves to LitRedis.Core 6.0.0.

@JacobAtchley
JacobAtchley merged commit 568550d into main Oct 8, 2026
2 checks passed
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.

2 participants