1414
1515namespace Microsoft . AspNetCore . Components . Infrastructure ;
1616
17- internal class PersistentServicesRegistry
17+ internal sealed class PersistentServicesRegistry
1818{
1919 private static readonly string _registryKey = typeof ( PersistentServicesRegistry ) . FullName ! ;
2020
@@ -23,60 +23,54 @@ internal class PersistentServicesRegistry
2323 private IPersistentComponentRegistration [ ] _registrations ;
2424 private List < PersistingComponentStateSubscription > _subscriptions = [ ] ;
2525 private static readonly ConcurrentDictionary < Type , PropertiesAccessor > _cachedAccessorsByType = new ( ) ;
26-
2726 public IComponentRenderMode ? RenderMode { get ; internal set ; }
2827
2928 public PersistentServicesRegistry ( IServiceProvider serviceProvider )
3029 {
3130 var registrations = serviceProvider . GetRequiredService < IEnumerable < IPersistentComponentRegistration > > ( ) ;
3231 _serviceProvider = serviceProvider ;
3332 _persistentServiceTypeCache = new PersistentServiceTypeCache ( ) ;
34- _registrations = [ .. registrations . Distinct ( ) . Order ( ) ] ;
35- }
36-
37- [ DebuggerDisplay ( $ "{{{nameof(GetDebuggerDisplay)}(),nq}}") ]
38- private class PersistentComponentRegistration : IPersistentComponentRegistration
39- {
40- public string Assembly { get ; set ; } = "" ;
41-
42- public string FullTypeName { get ; set ; } = "" ;
43-
44- public IComponentRenderMode ? GetRenderModeOrDefault ( ) => null ;
45-
46- private string GetDebuggerDisplay ( ) => $ "{ Assembly } ::{ FullTypeName } ";
33+ _registrations = [ .. registrations . DistinctBy ( r => ( r . Assembly , r . FullTypeName ) ) . OrderBy ( r => r . Assembly ) . ThenBy ( r => r . FullTypeName ) ] ;
4734 }
4835
4936 [ UnconditionalSuppressMessage ( "Trimming" , "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code" , Justification = "<Pending>" ) ]
50- private void RestoreRegistrationsIfAvailable ( PersistentComponentState state )
37+ internal void RegisterForPersistence ( PersistentComponentState state )
5138 {
52- foreach ( var registration in _registrations )
39+ if ( _subscriptions . Count != 0 )
5340 {
41+ return ;
42+ }
43+
44+ var subscriptions = new List < PersistingComponentStateSubscription > ( _registrations . Length + 1 ) ;
45+ for ( var i = 0 ; i < _registrations . Length ; i ++ )
46+ {
47+ var registration = _registrations [ i ] ;
5448 var type = ResolveType ( registration . Assembly , registration . FullTypeName ) ;
5549 if ( type == null )
5650 {
5751 continue ;
5852 }
5953
60- var instance = _serviceProvider . GetService ( type ) ;
61- if ( instance != null )
54+ var renderMode = registration . GetRenderModeOrDefault ( ) ;
55+
56+ var instance = _serviceProvider . GetRequiredService ( type ) ;
57+ subscriptions . Add ( state . RegisterOnPersisting ( ( ) =>
6258 {
63- RestoreInstanceState ( instance , type , state ) ;
64- }
59+ PersistInstanceState ( instance , type , state ) ;
60+ return Task . CompletedTask ;
61+ } , renderMode ) ) ;
6562 }
66- }
6763
68- [ RequiresUnreferencedCode ( "Calls Microsoft.AspNetCore.Components.PersistentComponentState.TryTakeFromJson(String, Type, out Object)" ) ]
69- private static void RestoreInstanceState ( object instance , Type type , PersistentComponentState state )
70- {
71- var accessors = _cachedAccessorsByType . GetOrAdd ( instance . GetType ( ) , static ( runtimeType , declaredType ) => new PropertiesAccessor ( runtimeType , declaredType ) , type ) ;
72- foreach ( var ( key , propertyType ) in accessors . KeyTypePairs )
64+ if ( RenderMode != null )
7365 {
74- if ( state . TryTakeFromJson ( key , propertyType , out var result ) )
66+ subscriptions . Add ( state . RegisterOnPersisting ( ( ) =>
7567 {
76- var ( setter , getter ) = accessors . GetAccessor ( key ) ;
77- setter . SetValue ( instance , result ! ) ;
78- }
68+ state . PersistAsJson ( _registryKey , _registrations ) ;
69+ return Task . CompletedTask ;
70+ } , RenderMode ) ) ;
7971 }
72+
73+ _subscriptions = subscriptions ;
8074 }
8175
8276 [ RequiresUnreferencedCode ( "Calls Microsoft.AspNetCore.Components.PersistentComponentState.PersistAsJson(String, Object, Type)" ) ]
@@ -94,8 +88,6 @@ private static void PersistInstanceState(object instance, Type type, PersistentC
9488 }
9589 }
9690
97- private Type ? ResolveType ( string assembly , string fullTypeName ) => _persistentServiceTypeCache . GetPersistentService ( assembly , fullTypeName ) ;
98-
9991 [ UnconditionalSuppressMessage ( "Trimming" , "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code" , Justification = "<Pending>" ) ]
10092 internal void Restore ( PersistentComponentState state )
10193 {
@@ -110,45 +102,41 @@ internal void Restore(PersistentComponentState state)
110102 }
111103
112104 [ UnconditionalSuppressMessage ( "Trimming" , "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code" , Justification = "<Pending>" ) ]
113- internal void RegisterForPersistence ( PersistentComponentState state )
105+ private void RestoreRegistrationsIfAvailable ( PersistentComponentState state )
114106 {
115- if ( _subscriptions . Count != 0 )
116- {
117- return ;
118- }
119-
120- var subscriptions = new List < PersistingComponentStateSubscription > ( _registrations . Length + 1 ) ;
121- for ( var i = 0 ; i < _registrations . Length ; i ++ )
107+ foreach ( var registration in _registrations )
122108 {
123- var registration = _registrations [ i ] ;
124109 var type = ResolveType ( registration . Assembly , registration . FullTypeName ) ;
125110 if ( type == null )
126111 {
127112 continue ;
128113 }
129114
130- var renderMode = registration . GetRenderModeOrDefault ( ) ;
131-
132- var instance = _serviceProvider . GetRequiredService ( type ) ;
133- subscriptions . Add ( state . RegisterOnPersisting ( ( ) =>
115+ var instance = _serviceProvider . GetService ( type ) ;
116+ if ( instance != null )
134117 {
135- PersistInstanceState ( instance , type , state ) ;
136- return Task . CompletedTask ;
137- } , renderMode ) ) ;
118+ RestoreInstanceState ( instance , type , state ) ;
119+ }
138120 }
121+ }
139122
140- if ( RenderMode != null )
123+ [ RequiresUnreferencedCode ( "Calls Microsoft.AspNetCore.Components.PersistentComponentState.TryTakeFromJson(String, Type, out Object)" ) ]
124+ private static void RestoreInstanceState ( object instance , Type type , PersistentComponentState state )
125+ {
126+ var accessors = _cachedAccessorsByType . GetOrAdd ( instance . GetType ( ) , static ( runtimeType , declaredType ) => new PropertiesAccessor ( runtimeType , declaredType ) , type ) ;
127+ foreach ( var ( key , propertyType ) in accessors . KeyTypePairs )
141128 {
142- subscriptions . Add ( state . RegisterOnPersisting ( ( ) =>
129+ if ( state . TryTakeFromJson ( key , propertyType , out var result ) )
143130 {
144- state . PersistAsJson ( _registryKey , _registrations ) ;
145- return Task . CompletedTask ;
146- } , RenderMode ) ) ;
131+ var ( setter , getter ) = accessors . GetAccessor ( key ) ;
132+ setter . SetValue ( instance , result ! ) ;
133+ }
147134 }
148-
149- _subscriptions = subscriptions ;
150135 }
151136
137+
138+ private Type ? ResolveType ( string assembly , string fullTypeName ) => _persistentServiceTypeCache . GetPersistentService ( assembly , fullTypeName ) ;
139+
152140 private sealed class PropertiesAccessor
153141 {
154142 internal const BindingFlags BindablePropertyFlags = BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance | BindingFlags . IgnoreCase ;
@@ -216,21 +204,19 @@ internal static IEnumerable<PropertyInfo> GetCandidateBindableProperties(
216204 [ DynamicallyAccessedMembers ( LinkerFlags . Component ) ] Type targetType )
217205 => MemberAssignment . GetPropertiesIncludingInherited ( targetType , BindablePropertyFlags ) ;
218206
219- internal ( PropertySetter setter , PropertyGetter getter ) GetAccessor ( string key )
220- {
221- return _underlyingAccessors . TryGetValue ( key , out var result ) ? result : default ;
222- }
207+ internal ( PropertySetter setter , PropertyGetter getter ) GetAccessor ( string key ) =>
208+ _underlyingAccessors . TryGetValue ( key , out var result ) ? result : default ;
223209 }
224210
225- private class RenderModeComparer : IEqualityComparer < IComponentRenderMode ? >
211+ [ DebuggerDisplay ( $ "{{{nameof(GetDebuggerDisplay)}(),nq}}") ]
212+ private class PersistentComponentRegistration : IPersistentComponentRegistration
226213 {
227- public static RenderModeComparer Instance { get ; } = new RenderModeComparer ( ) ;
214+ public string Assembly { get ; set ; } = "" ;
228215
229- public bool Equals ( IComponentRenderMode ? x , IComponentRenderMode ? y )
230- {
231- return x ? . GetType ( ) == y ? . GetType ( ) ;
232- }
216+ public string FullTypeName { get ; set ; } = "" ;
233217
234- public int GetHashCode ( [ DisallowNull ] IComponentRenderMode ? obj ) => obj ? . GetHashCode ( ) ?? 1 ;
218+ public IComponentRenderMode ? GetRenderModeOrDefault ( ) => null ;
219+
220+ private string GetDebuggerDisplay ( ) => $ "{ Assembly } ::{ FullTypeName } ";
235221 }
236222}
0 commit comments