[Validation] CacheView backed by HybridCache
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
**Scenario contact:** @dariatiurina
## Scenario
`CacheView` uses an in-memory store by default, so every instance warms its own copy and a restart throws it all away. With `HybridCache` and a shared distributed backing store, an instance can reuse an entry created by another. HybridCache still has a local primary cache, so not every hit reaches the distributed store. Sliding expiration is unavailable on this CacheView store.
Validate shared-entry reuse and the sliding-expiration diagnostic. Characterize the configured provider's behavior during an outage separately, distinguishing local hits, failed backend access, and recovery.
## Minimum build
.NET 11 RC1.
## Configurations to cover
* Blazor Web App
* [x] Static SSR
* [ ] Interactive Server
* [ ] Interactive WebAssembly
* [ ] Interactive Auto
* [ ] Standalone WebAssembly
* [ ] Hybrid (MAUI)
## Also exercise
* [ ] Published output
* [ ] An existing .NET 10 app upgraded to .NET 11
* [ ] Trimming or ahead-of-time compilation
* [x] More than one server instance, or a proxy in front
* [ ] Hot Reload
* [ ] An IDE as well as the command line
* [ ] Container
Sharing entries between instances is the point of the feature, so more than one instance is mandatory here.
## Setup
Run two instances of the same built app behind a proxy with no sticky sessions, using matching cache configuration and a shared Redis or other distributed backing store with `HybridCache` registered. Keep the cache lifetime long enough for the restart comparisons. Collect Debug-level logs for the Components, HybridCache, and distributed-provider categories on both instances, since failures can be handled at different layers.
## What to build
A page with a `CacheView` containing a child that creates and displays a `Guid` during initialization, plus a line outside the section identifying the responding instance. Log the child's initialization so reuse on a second instance is distinguishable from rerendering.
Work out from the docs whether registering `HybridCache` is enough on its own or whether the cache must be selected explicitly. Record the answer: registering HybridCache for unrelated reasons might change where render output is cached.
Add absolute and relative expiration sections and a section large enough to exercise a deliberately small payload limit. Put the unsupported sliding-expiration section on a separate page, so its expected exception does not block the sharing and recovery cases.
Keep a second copy of the app with one visible word changed inside the cached section, so you can run the two side by side against the same store.
## Things to try
* Warm the page on one instance, then request it repeatedly and check whether the other instance serves the same entry.
* Restart one instance and request the page from it immediately.
* Restart both in turn and count how many times the section actually rendered.
* Load the separate sliding-expiration page and record when its error appears.
* Check the absolute and elapsed-time expirations behave as they did in memory.
* Stop the backing store. Compare requests for already-warm local entries with requests for a new key that must attempt a backend lookup. Start the store again without restarting the app, then use a fresh key to check sharing resumes.
* Configure a small payload limit and request a new oversized entry. Record whether it is rejected by the limit, whether a storage operation throws, what is logged, and what the visitor receives. Do not assume these are the same failure path.
* Run the changed copy on one instance and the original on the other against the same store, and record which version's text visitors get from each.
* Record cold, local-cache-hit, and secondary-cache-hit load times as observations, identifying which cache layer actually served each request.
## Expected behavior
An instance with empty local memory can reuse an unexpired shared entry with the same effective key. Sliding expiration is rejected. A backing-store outage does not invalidate otherwise usable local entries, and cache failures should not be confused with errors in the component being rendered.
### Must hold
* A page warmed on the first instance is served by the second with the same `Guid`, and the second instance does not render the section.
* An instance restarted with the same app and configuration serves an unexpired shared entry without re-rendering.
* Sliding expiration with this store throws `NotSupportedException` whose message names the sliding option and points at the absolute alternatives; absolute expiration configured the same way works.
* A failure to persist a newly rendered entry does not prevent that rendered response from reaching the visitor, and the failure is reported by the layer handling it.
### Expected differences between configurations
* A local-cache hit does not need a secondary-store round trip. Timing depends on the cache layer, application work, and environment; no ordering of elapsed times is required.
* Sliding expiration works on the default in-memory store and not on this one.
* During the mixed-version experiment, record each instance's output and effective key configuration. Do not assume that changing a visible word alone guarantees matching keys, compatible serialized metadata, or any particular rolling-deployment result.
## Evidence to capture
* Request logs from both instances for the warm-on-one, served-by-the-other test, with the `Guid` and instance line visible.
* The verbatim sliding-expiration message and where it surfaced.
* Request outcomes and log excerpts during the store outage and after recovery, identifying local hits separately from actual backend attempts, plus logs for a rejected payload.
## Documentation to use
* [ASP.NET Core Blazor CacheView component](https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management/cacheview-component?view=aspnetcore-11.0)
* [HybridCache library in ASP.NET Core](https://learn.microsoft.com/aspnet/core/performance/caching/hybrid?view=aspnetcore-11.0)
Report whether the docs say that registering `HybridCache` changes where render output is cached, and whether the sliding expiration limitation is documented rather than only enforced at runtime.
## What to report
Report results using the format described in the [validation testing manual](https://github.com/dotnet/aspnetcore/issues/68479). Include link to a repository with the test app.
Contributor guide
Research direction
Start with the CacheView and HybridCache documentation, then follow the validation testing manual at issue 68479. Build the .NET 11 RC1 Blazor app described in the issue with two instances, a shared Redis store, and the required logging. Done means a repository and report containing the cross-instance, expiration, outage, payload-limit, and mixed-version observations with captured evidence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, redis
- Domain
- backend, distributed-systems, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 42/100