Constructor injection in Components was ruled out previously as "we don't plan to do this" but now that we have partials is there any change in this attitude?
see #15779 , #5497
If Blazor could be modified to optionally use DI to source components, then constructor injection would be possible,
If you would be open to at least reviewing a PR, I'm sure the community would do the groundwork to make it happen.
Thanks for your issue report. We'll consider whether to address this during our next milestone planning.
Thanks for that
This is a must have. Property based injection prevents us from consuming them within the constructor there by preventing us from making some (other) fields read only.
Comment from a duplicate issue I opened:
Currently blazor only allows injecting services into components using property injection via the [Inject]
attribute.
However this has a number of disadvantages over constructor injection
If there is a single constructor, use it for dependency injection. It is an error if any of the parameters cannot be resolved. It is an error if there are multiple constructors, none of which are parameterless, unless one of them is marked with [Inject]
. After the construction, property injection takes place.
InjectAttribute
cannot be set on non-properties. There is already ActivatorUtilitiesConstructorAttribute
available for decorating a constructor to be used by DI.
Any updates on this? @pranavkm
Moving to backlog given this now be achieved using IComponentActivator
.
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.
@mkArtakMSFT how can it be achieved using IComponentActivator? Could you please give an example?
@janissimsons,
As I can see, IComponentActivator
is a service that is used when the renderer needs to create a new component instance.
The default implementation is DefaultComponentActivator which uses the Activator.CreateInstance
.
So, you can just implement the IComponentActivator
, inject the IServiceProvider
into your implementation and use the .GetService(Type)
method to create the compoent. I suggest to fallback the Activator.CreateInstance
if GetService returns null (that means the component hasn't registered to the DI).
Then you need to register your components to the DI.
The implementation can be like that:
````csharp
using System;
using Microsoft.AspNetCore.Components;
namespace MyProject
{
public class ServiceProviderComponentActivator : IComponentActivator
{
public IServiceProvider ServiceProvider { get; }
public ServiceProviderComponentActivator(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public IComponent CreateInstance(Type componentType)
{
var instance = ServiceProvider.GetService(componentType);
if (instance == null)
{
instance = Activator.CreateInstance(componentType);
}
if (!(instance is IComponent component))
{
throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType));
}
return component;
}
}
}
````
Then replace the IComponentActivator
service:
csharp
services.Replace(ServiceDescriptor.Transient<IComponentActivator, ServiceProviderComponentActivator>());
@mkArtakMSFT is there any problem with this implementation? Does it cause a memory leak (I don't know how the IServiceProvider scope is managed for this case)?
Keep in mind that this only works in .net 5. I wish this was the done by default. But this will do it for me.
Most helpful comment
Thanks for your issue report. We'll consider whether to address this during our next milestone planning.