Skip to content

Add HybridCache.GetOrCreateAsync overloads for dynamic setting of options#129048

Merged
svick merged 19 commits into
dotnet:mainfrom
svick:api-proposal/hybridcache
Jul 16, 2026
Merged

Add HybridCache.GetOrCreateAsync overloads for dynamic setting of options#129048
svick merged 19 commits into
dotnet:mainfrom
svick:api-proposal/hybridcache

Conversation

@svick

@svick svick commented Jun 5, 2026

Copy link
Copy Markdown
Member

Implements the API proposals approved in #121530 and #114366.

There is a companion PR at dotnet/extensions#7568.

Important

The public HybridCacheEntryContext constructor (see below) is awaiting API review approval — it is not part of the currently approved API, which specifies an internal constructor. See the rationale under HybridCacheEntryContext.

Changes

HybridCacheEntryOptions (immutable + LocalSize)

  • Expiration, LocalCacheExpiration, and Flags remain init-only (immutable), as originally shipped.
  • New LocalSize property (init) to control the size assigned to the local (L1) cache entry (e.g. MemoryCache.Size).

HybridCacheEntryContext (mutable factory view)

New sealed type handed to the options-aware factory callbacks so they can influence cache entry options based on the produced value:

  • Mutable Expiration, LocalCacheExpiration, Flags, and LocalSize (seeded from the effective options).
  • Revision property that increments on each property change, allowing implementations to detect whether the factory changed anything.
  • Public HybridCacheEntryContext(HybridCacheEntryOptions?) constructor that seeds the context from the effective options, so third-party HybridCache implementations can construct and populate a context in one line. The approved API specifies an internal constructor; making it public is awaiting API review approval.

HybridCache (context-aware factory overloads)

New virtual GetOrCreateAsync overloads that take a Func<…, HybridCacheEntryContext, CancellationToken, ValueTask<T>> factory, mirroring the existing key-shape family (string, ReadOnlySpan<char>, DefaultInterpolatedStringHandler) with both TState and no-TState variants.

The default implementation seeds a HybridCacheEntryContext from the effective options, invokes the factory with local/distributed writes suppressed, and then performs a single SetAsync using the (possibly factory-mutated) options — preserving backward compatibility for existing HybridCache implementations. Implementations should override the new virtual to honor factory-supplied values natively (using Revision for mutation detection).

Tests

Added contract tests for the default GetOrCreateAsync implementation, exercised against a fake in-memory HybridCache so any correct default implementation passes.

Note

This PR description was updated with the assistance of GitHub Copilot.

svick and others added 9 commits April 22, 2026 15:46
…loads

Introduce HybridCacheFactoryContext, a new type passed to the factory callback
in GetOrCreateAsync, allowing the factory to dynamically influence cache entry
options based on the result of the data fetch.

The context exposes:
- Expiration / LocalCacheExpiration: override entry lifetime (dotnet#121530)
- Flags: override write-side cache flags, e.g. skip caching (dotnet#121530)
- LocalCacheSize: set L1 cache entry size for MemoryCache SizeLimit (dotnet#114366)

New virtual GetOrCreateAsync overloads mirror the existing key-shape family
(string, ReadOnlySpan<char>, DefaultInterpolatedStringHandler) with both
TState and no-TState variants.

The default implementation wraps the context-aware factory and delegates to
the existing abstract overload, preserving backward compatibility for
existing HybridCache implementations. Implementations should override the
new virtual method to honor context values.

Contributes to dotnet#114366
Contributes to dotnet#121530

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add missing <summary> tag for LocalCacheExpiration and fix 'Gets or set'
typo on Expiration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clarify that DisableCompression is a write-side flag (honored from context)
and DisableUnderlyingData is a read-side flag (ignored from context).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…entOptions and LocalCacheSize

Implements API proposals in dotnet#114366 and dotnet#121530:

- Rename HybridCacheFactoryContext to HybridCacheEntryContext.

- Add HybridCacheEntryContext(HybridCacheEntryOptions currentOptions) constructor and CurrentOptions property.

- Add LocalCacheSize init-only property to HybridCacheEntryOptions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 5, 2026 16:06
@dotnet-policy-service dotnet-policy-service Bot added the linkable-framework Issues associated with delivering a linker friendly framework label Jun 5, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-caching
See info in area-owners.md if you want to be subscribed.

Copilot AI 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.

Pull request overview

This PR expands Microsoft.Extensions.Caching.Hybrid.HybridCache with new GetOrCreateAsync overloads where the factory callback receives a mutable HybridCacheEntryOptions, enabling per-entry option adjustments at runtime (e.g., expiration, flags, local size). It also updates HybridCacheEntryOptions to support mutation tracking via Revision, adds LocalSize, and includes trimming and package-compat scaffolding for the new shape.

Changes:

  • Make HybridCacheEntryOptions properties mutable (get; set;), add LocalSize, and add Revision mutation tracking (plus internal helpers).
  • Add new (virtual) HybridCache.GetOrCreateAsync overloads whose factory receives HybridCacheEntryOptions (string + NET-only key shapes).
  • Add trimming descriptor entries for internal helpers and add package compatibility suppressions for initset changes.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCacheEntryOptions.cs Makes options mutable, adds LocalSize and Revision, plus internal clone/translation helpers.
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCache.cs Introduces options-aware GetOrCreateAsync overloads and a default implementation bridging to the existing abstract overload.
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/ILLink/ILLink.Descriptors.LibraryBuild.xml Preserves internal members accessed cross-assembly via UnsafeAccessor for trimming.
src/libraries/Microsoft.Extensions.Caching.Abstractions/src/CompatibilitySuppressions.xml Adds package validation suppressions for the accessor-shape change.
src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.cs Updates the public API contract for HybridCacheEntryOptions and adds the new string-key overloads.
src/libraries/Microsoft.Extensions.Caching.Abstractions/ref/Microsoft.Extensions.Caching.Abstractions.net10.cs Adds NET-only key-shape overloads for the new factory signature.

Comment thread src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCache.cs Outdated
Copilot AI review requested due to automatic review settings July 9, 2026 13:52

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCache.cs Outdated
… overloads

Cover the new context-aware GetOrCreateAsync overloads for the ReadOnlySpan<char>
and DefaultInterpolatedStringHandler key shapes (previously only string keys were
tested): the factory receives a context and its mutations reach the cache write,
and for the interpolated-string handler the key is cleared on both the async
(factory ran) and synchronous (cache hit) completion paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 14:45
The type-level remarks implied the properties are always initialized to the
effective values for the operation. That only holds when a HybridCache
implementation seeds the context for a factory callback; a directly constructed
context reflects only the options passed to its constructor. Clarify the remarks
accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCache.cs Outdated
Copilot AI review requested due to automatic review settings July 9, 2026 14:54
Replace the four explicit backing fields with the field keyword in each property
setter. The constructor now seeds through the setters and resets Revision to zero
so a freshly seeded context still reports no caller changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Copilot AI review requested due to automatic review settings July 9, 2026 15:04
The properties are init-only but still settable by the caller at construction, so
the documentation should follow the standard 'Gets or sets' phrasing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Comment thread src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCache.cs Outdated
Copilot AI review requested due to automatic review settings July 9, 2026 15:12

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

…in default GetOrCreateAsync

- Create/seed the HybridCacheEntryContext lazily inside the wrapped factory delegate,
  so a cache hit (where the factory never runs) no longer allocates a context. The
  DefaultImplState now carries the original options and receives the context back
  (a non-null context signals the factory ran, replacing the FactoryRan flag).
- Reuse a shared immutable write-disabled options instance for the common options == null
  case instead of cloning per call.
- Only materialize new options for the trailing SetAsync when the factory actually mutated
  the context (Revision != 0); otherwise reuse the caller's original options, avoiding an
  allocation and preserving null-options semantics that implementations may treat specially.
- Add a contract test covering the unchanged-context path preserving null options.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 16:17

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

@svick
svick marked this pull request as ready for review July 15, 2026 12:33
@svick
svick requested a review from rosebyte July 15, 2026 12:33
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
12 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@svick
svick merged commit e5fc966 into dotnet:main Jul 16, 2026
89 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Extensions-Caching linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants