-
Notifications
You must be signed in to change notification settings - Fork 10.3k
[Blazor] Support for declaratively persisting component and services state #60634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Blazor] Support for declaratively persisting component and services state #60634
Conversation
55fa34d
to
6e6bd2d
Compare
@@ -11777,6 +11790,8 @@ Global | |||
{01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} = {225AEDCF-7162-4A86-AC74-06B84660B379} | |||
{E6D564C0-4CA5-411C-BF40-9802AF7900CB} = {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} | |||
{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157} = {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} | |||
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {60D51C98-2CC0-40DF-B338-44154EFEE2FF} | |||
{E22DD5A6-06E2-490E-BD32-88D629FD6668} = {60D51C98-2CC0-40DF-B338-44154EFEE2FF} | |||
EndGlobalSection | |||
GlobalSection(ExtensibilityGlobals) = postSolution | |||
SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just fixing the solution file that was broken.
src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs
Outdated
Show resolved
Hide resolved
I'm adding more tests, but the current implementation should be working for all mainline scenarios |
This pull request includes several changes aimed at enhancing the functionality and robustness of the ASP.NET Core components. The most significant changes involve the addition of new projects to the solution, modifications to cascading parameter state management, and improvements to persistent component state handling. Solution Structure Updates:
Cascading Parameter State Enhancements:
Persistent Component State Improvements:
These changes collectively improve the modularity, state management, and persistence capabilities of the ASP.NET Core components, making the framework more robust and easier to extend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Overview
This PR introduces initial support for persisting component state in Blazor by augmenting the existing persistence mechanism with a declarative model. Key changes include:
- New infrastructure for generating and caching unique keys for both component and service state.
- Extension methods and service registrations that integrate persistent state functionality for both components and services.
- Modifications to persistence state registration, restoration, and callback execution across the rendering and DI pipelines.
Reviewed Changes
File | Description |
---|---|
src/Components/Components/src/Reflection/PropertyGetter.cs | Introduces a generic property getter using dynamic code support. |
src/Components/Components/src/PersistentState/PersistentServiceTypeCache.cs | Adds a cache for resolving persistent service types. |
src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs | Implements service registration/restoration for persistent state. |
src/Components/Components/src/SupplyParameterFromPersistentComponentStateProviderServiceCollectionExtensions.cs | Provides extension methods for persistent state-related service registration. |
src/Components/Components/src/SupplyParameterFromPersistentComponentStateValueProvider.cs | Adds a value provider to supply component parameters from persistent state. |
src/Components/Components/src/PersistentComponentState.cs | Updates the component state management to include persistence callbacks. |
src/Components/Components/src/RenderTree/Renderer.cs and others | Integrates persistent state behavior with component registration and cascading parameters. |
src/Components/Components/test/Lifetime/ComponentStatePersistenceManagerTest.cs | Updates tests to reflect the new persistent state service registration. |
src/Components/Components/src/ParameterView.cs | Adjusts cascading parameter lookup to incorporate a derived key. |
Copilot reviewed 30 out of 30 changed files in this pull request and generated 4 comments.
src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs
Show resolved
Hide resolved
src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs
Outdated
Show resolved
Hide resolved
src/Components/Components/src/SupplyParameterFromPersistentComponentStateValueProvider.cs
Show resolved
Hide resolved
1c54a24
to
995d550
Compare
src/Components/Components/src/PersistentState/PersistentServiceTypeCache.cs
Outdated
Show resolved
Hide resolved
src/Components/Components/src/SupplyParameterFromPersistentComponentStateValueProvider.cs
Outdated
Show resolved
Hide resolved
src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs
Show resolved
Hide resolved
997105b
to
245624e
Compare
src/Components/Components/src/SupplyParameterFromPersistentComponentStateValueProvider.cs
Outdated
Show resolved
Hide resolved
src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs
Show resolved
Hide resolved
src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs
Outdated
Show resolved
Hide resolved
src/Components/Components/src/PersistentState/IPersistentComponentRegistration.cs
Outdated
Show resolved
Hide resolved
src/Components/Components/src/SupplyParameterFromPersistentComponentStateValueProvider.cs
Show resolved
Hide resolved
3c4cc13
to
bedbdf0
Compare
1cdfc6c
to
3478be9
Compare
I believe this PR caused a perf regression: It looks like lock contention potentially increased as well which may be causing the regression: |
Adds a declarative model for persistent component and services state
This PR augments the persistent component state feature with a declarative model that allows the developer to place an attribute on components and services properties to indicate that they should be persisted during prerendering so that it is accessible when the application becomes interactive.
Scenarios
Serializing state for a component
[SupplyParameterFromPersistentComponentState]
will be serialized and deserialized during prerendering.Serializing state for multiple components of the same type
ParentComponent.razor
ChildComponent.razor
[SupplyParameterFromPersistentComponentState]
will be serialized and deserialized during prerendering.@key
directive is used to ensure that the state is correctly associated with the component instance.Element
property is initialized in theOnInitialized
method to avoid null reference exceptions similarly to how we do it forquery parameters and form data.
Serializing state for a service
CounterService.cs
Program.cs
[SupplyParameterFromPersistentComponentState]
will be serialized during prerendering and deserialized when the application becomes interactive.AddPersistentService
method is used to register the service for persistence.RenderMode.Server
- The service will be available for interactive server mode.RenderMode.Webassembly
- The service will be available for interactive webassembly mode.RenderMode.InteractiveAuto
- The service will be available for both interactive server and webassembly modes if a component renders in any of those modes.[SupplyParameterFromPersistentComponentState]
will be deserialized.Implementation details
Key Computation
For components
We need to generate a unique key for each property that needs to be persisted. For components, this key is computed based on:
@key
directive if present and serializable (e.g.,Guid
,DateOnly
,TimeOnly
, and primitive types)The key computation ensures that even if multiple instances of the same component are present on the page (for example, in a loop), each instance's state can be uniquely identified and persisted.
The key computation algorithm only takes into account a small subset of a component hierarchy for performance reasons. This limits the ability to persist state on recursive component hierarchies. Our recommendation for those scenarios is to persist the state at the top level of the hierarchy.
It's also important to indicate that the imperative API is still available for more advanced scenarios, which offers more flexibility on how to handle the more complex cases.
For services
Only persisting scoped services is supported. We need to generate a unique key for each property that needs to be persisted. The key for services is derived from:
Properties to be serialized are identified from the actual service instance.
Serialization and Deserialization
By default properties are serialized using the System.Text.Json serializer with default settings. Note that this method is not trimmer safe and requires the user to ensure that the types used are preserved through some other means.
This is consistent with our usage of System.Text.Json across other areas of the product, like root component parameters or JSInterop.
We plan to add an extensibility point to control the serialization mechanism used in this scenario in a future change.