dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.44k stars 10.02k forks source link

Allow the interception of property injection with Blazor Components #28957

Open dotnetjunkie opened 3 years ago

dotnetjunkie commented 3 years ago

After a previous discussion (https://github.com/dotnet/aspnetcore/issues/8886), the IComponentActivator abstraction was introduced in .NET 5 (#19642). Unfortunately, implementations of this new abstraction are not expected to apply any injection, as the documentation for IComponentActivator states:

The activator is not responsible for dependency injection, since the framework performs dependency injection to the resulting instances separately.

Instead, the "responsibility for dependency injection", i.e. property injection, is implemented in the ComponentFactory class. The implementation of property injection, however, is hard coded to use the IServiceProvider abstraction. There is no way to intercept this behavior and ComponentFactory is internal with no option to replace it.

This, unfortunately, makes the given IComponentActivator abstraction useless from a DI perspective (as proposed in #8886). While non-conforming containers would like to intercept the composition of object graphs of Blazor components (including the composition of all their dependencies), they can only intercept the creation of the Blazor component itself; not the injection of its dependencies, because ComponentFactory is responsible for this. A non-conforming container, however, does not replace the built-in container, and when ComponentFactory calls IServiceProvider, it requests the dependency from the built-in container, not from the non-conforming container. As such dependency would not be part of the built-in container, ComponentFactory will throw the following exception:

Cannot provide a value for property '{propertyName}' on type '{type.FullName}'. There is no registered service of type '{propertyType}'.

To work around this situation, users of a non-conforming container would have to:

Neither of the two options above are practical or desirable and we should try to improve integration to make this possible.

I see two possible solutions:

  1. Move property injection out of ComponentFactory into DefaultComponentActivator and make DefaultComponentActivator public. This allows replacing property injection behavior by intercepting IComponentActivator. By making DefaultComponentActivator public, a custom IComponentActivator implementation can forward the call to the default implementation for framework components, which is important because it will be responsible for doing property injection on framework components.
  2. Add a new abstraction that allows intercepting property injection. Such hypothetical IComponentInitializer abstraction could have a void Initialize(IComponent) method that applies property injection where the framework's DefaultComponentInitializer would get injection logic and caching that is currently part of ComponentFactory.

Both options have their pros and cons:

Perhaps there are other options to consider. If you think there are, please post your ideas below.

/cc @davidfowl

mkArtakMSFT commented 3 years ago

Thanks for contacting us. @davidfowl please let us know what needs to happen here.

ghost commented 3 years ago

Thanks for contacting us. We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost commented 3 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost commented 11 months ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.