Background and Motivation
Currently, Blazor's property injection logic (for [Inject] attributes) is embedded within the internal ComponentFactory class with no public extension point. While IComponentActivator exists for customizing component instantiation, there is no equivalent mechanism for property injection.
This creates a gap for advanced scenarios such as:
- Blazor Hybrid with .NET MAUI: Additional platform-specific context may be needed for property resolution
- Custom DI containers: May need to intercept property injection for custom behavior
- Testing scenarios: Easier mocking and verification of property injection
We cannot extend IComponentActivator to handle property injection as that would be a breaking change for existing custom implementations. Following the pattern established by MVC (which defines separate activators for tag helpers, view components, controllers, and Razor Pages), we propose introducing a separate IComponentPropertyActivator interface specifically for property activation.
Proposed API
namespace Microsoft.AspNetCore.Components;
+ /// <summary>
+ /// Provides a mechanism for activating properties on Blazor component instances.
+ /// </summary>
+ public interface IComponentPropertyActivator
+ {
+ /// <summary>
+ /// Gets a delegate that activates properties on a component of the specified type.
+ /// </summary>
+ /// <param name="componentType">The type of component to create an activator for.</param>
+ /// <returns>
+ /// A delegate that takes an IServiceProvider and an IComponent
+ /// instance, and populates the component's injectable properties.
+ /// </returns>
+ Action<IServiceProvider, IComponent> GetActivator(
+ [DynamicallyAccessedMembers(Component)] Type componentType);
+ }
From PublicAPI.Unshipped.txt:
Microsoft.AspNetCore.Components.IComponentPropertyActivator
Microsoft.AspNetCore.Components.IComponentPropertyActivator.GetActivator(System.Type! componentType) -> System.Action<System.IServiceProvider!, Microsoft.AspNetCore.Components.IComponent!>!
Usage Examples
Custom Implementation:
public class CustomPropertyActivator : IComponentPropertyActivator
{
public Action<IServiceProvider, IComponent> GetActivator(Type componentType)
{
// Custom property injection logic with caching
return (serviceProvider, component) =>
{
// Inject properties with custom behavior
// e.g., logging, platform-specific resolution, etc.
};
}
}
Registration:
// In Startup.cs or Program.cs
services.AddSingleton<IComponentPropertyActivator, CustomPropertyActivator>();
Default Behavior (for reference - this is internal):
The framework provides DefaultComponentPropertyActivator internally which:
- Discovers properties marked with
[Inject]
- Supports keyed services via
[Inject(Key = "...")]
- Caches activator delegates per component type
- Integrates with Hot Reload for cache invalidation
Alternative Designs
-
Extend IComponentActivator: We considered adding property injection responsibility to the existing IComponentActivator interface. However, this would be a breaking change for existing custom implementations that don't expect to handle property injection.
-
Context object parameter: The original issue mentioned considering a context object for future-proofing. We opted for the simpler IServiceProvider parameter to match the existing Blazor patterns (consistent with IComponentActivator) and avoid unnecessary complexity. If additional context is needed in the future, a new overload or interface version can be introduced.
-
MVC's context-based pattern: MVC activators like ITagHelperActivator use context objects (e.g., ViewContext). We chose the direct IServiceProvider approach to maintain consistency with existing Blazor APIs and because Blazor's rendering context is already available through other means.
Risks
-
Interface extensibility: The interface has a single method. If we need to add more methods in the future, we would need to add default implementations or introduce a new interface version to avoid breaking changes.
-
Performance considerations: Custom implementations should cache activator delegates (as the default implementation does) to avoid repeated reflection costs. Poor implementations could cause performance regressions.
-
No breaking changes identified: This is a purely additive change. The default behavior remains unchanged for applications that don't register a custom IComponentPropertyActivator.
Implementation: #64595
Related Issue: #63451
Background and Motivation
Currently, Blazor's property injection logic (for
[Inject]attributes) is embedded within the internalComponentFactoryclass with no public extension point. WhileIComponentActivatorexists for customizing component instantiation, there is no equivalent mechanism for property injection.This creates a gap for advanced scenarios such as:
We cannot extend
IComponentActivatorto handle property injection as that would be a breaking change for existing custom implementations. Following the pattern established by MVC (which defines separate activators for tag helpers, view components, controllers, and Razor Pages), we propose introducing a separateIComponentPropertyActivatorinterface specifically for property activation.Proposed API
From
PublicAPI.Unshipped.txt:Usage Examples
Custom Implementation:
Registration:
Default Behavior (for reference - this is internal):
The framework provides
DefaultComponentPropertyActivatorinternally which:[Inject][Inject(Key = "...")]Alternative Designs
Extend
IComponentActivator: We considered adding property injection responsibility to the existingIComponentActivatorinterface. However, this would be a breaking change for existing custom implementations that don't expect to handle property injection.Context object parameter: The original issue mentioned considering a context object for future-proofing. We opted for the simpler
IServiceProviderparameter to match the existing Blazor patterns (consistent withIComponentActivator) and avoid unnecessary complexity. If additional context is needed in the future, a new overload or interface version can be introduced.MVC's context-based pattern: MVC activators like
ITagHelperActivatoruse context objects (e.g.,ViewContext). We chose the directIServiceProviderapproach to maintain consistency with existing Blazor APIs and because Blazor's rendering context is already available through other means.Risks
Interface extensibility: The interface has a single method. If we need to add more methods in the future, we would need to add default implementations or introduce a new interface version to avoid breaking changes.
Performance considerations: Custom implementations should cache activator delegates (as the default implementation does) to avoid repeated reflection costs. Poor implementations could cause performance regressions.
No breaking changes identified: This is a purely additive change. The default behavior remains unchanged for applications that don't register a custom
IComponentPropertyActivator.Implementation: #64595
Related Issue: #63451