@@ -286,36 +286,68 @@ The analyzer helps catch performance issues where `InvokeAsync` is unnecessarily
286286
287287## `IComponentPropertyActivator` for custom property injection
288288
289- Blazor now provides a new `IComponentPropertyActivator ` interface for customizing property injection in components . This public abstraction enables advanced scenarios like custom DI containers , Blazor Hybrid scenarios , or specialized property resolution logic .
289+ Blazor now provides `IComponentPropertyActivator ` for customizing how `[Inject ]` properties are populated on components . This enables advanced scenarios like :
290+
291+ - Providing additional context for property resolution
292+ - Support for custom DI containers that need to intercept property injection
293+ - Advanced scenarios requiring property injection customization
290294
291295```csharp
292296public interface IComponentPropertyActivator
293297{
294- Action < IServiceProvider , object > GetActivator (
298+ Action < IServiceProvider , IComponent > GetActivator (
295299 [DynamicallyAccessedMembers (Component )] Type componentType );
296300}
297301```
298302
299- ** Usage : **
303+ ** Example : Logging property activator **
300304
301305```csharp
302- public class CustomPropertyActivator : IComponentPropertyActivator
306+ public class LoggingPropertyActivator : IComponentPropertyActivator
303307{
304- public Action < IServiceProvider , object > GetActivator (Type componentType )
308+ private readonly ILogger < LoggingPropertyActivator > _logger ;
309+ private readonly ConcurrentDictionary < Type , Action < IServiceProvider , IComponent >> _cache = new ();
310+
311+ public LoggingPropertyActivator (ILogger < LoggingPropertyActivator > logger )
312+ {
313+ _logger = logger ;
314+ }
315+
316+ public Action < IServiceProvider , IComponent > GetActivator (Type componentType )
305317 {
306- return ( serviceProvider , component ) =>
318+ return _cache . GetOrAdd ( componentType , type =>
307319 {
308- // Custom property injection logic
309- // Access component properties and inject dependencies
310- };
320+ var injectProperties = type
321+ .GetProperties (BindingFlags .Instance | BindingFlags .Public | BindingFlags .NonPublic )
322+ .Where (p => p .GetCustomAttribute <InjectAttribute >() != null )
323+ .ToList ();
324+
325+ return (serviceProvider , component ) =>
326+ {
327+ foreach (var property in injectProperties )
328+ {
329+ var injectAttr = property .GetCustomAttribute <InjectAttribute >();
330+ object ? service = injectAttr ? .Key != null
331+ ? serviceProvider .GetKeyedService (property .PropertyType , injectAttr .Key )
332+ : serviceProvider .GetService (property .PropertyType );
333+
334+ if (service != null )
335+ {
336+ _logger .LogDebug (" Injecting {Service} into {Component}.{Property}" ,
337+ property .PropertyType .Name , type .Name , property .Name );
338+ property .SetValue (component , service );
339+ }
340+ }
341+ };
342+ });
311343 }
312344}
313345
314- // Registration
315- services . AddSingleton <IComponentPropertyActivator , CustomPropertyActivator >();
346+ // Registration - replaces default property injection
347+ builder . Services . AddSingleton <IComponentPropertyActivator , LoggingPropertyActivator >();
316348```
317349
318- The interface follows the same pattern as MVC 's property activators and integrates with Hot Reload for cache invalidation. The default implementation supports keyed services via `[Inject(Key = "...")]` and includes proper trimming annotations for AOT compatibility.
350+ The default implementation caches activators per component type , supports keyed services via `[Inject (Key = " ..." )]`, integrates with Hot Reload for cache invalidation , and includes proper trimming annotations for AOT compatibility .
319351
320352## SignalR `ConfigureConnection` for Interactive Server components
321353
0 commit comments