Reputation: 15643
Question: It has been well documented, how to inject dependencies into services. However, is it also possible in ASP.NET Core 2.0 to have the system's DI mechanism automatically inject a dependency into a method or into a property? (similar to what is called setter injection in PHP-Symfony).
Example:
Say I have a common MyBaseController
class for all controllers in my project and I want a service (e.g. the UserManager service) to be injected into MyBaseController
that can be later accessed in all child controllers. I could use constructor injection to inject the service in the child class and pass it via base(userManager)
to the parent. But having to perform this in all child constructors of all controllers is pretty tedious.
So I would like to have a setter in MyBaseController
like this:
public abstract class MyBaseController : Controller
{
public UserManager<User> userManager { get; set; }
// system should auto inject UserManager here
public void setUserManager(UserManager<User> userManager) {
this.userManager = userManager;
}
}
...so I don't have to do the following in every child constructor just to pass the dependency to the parent:
public class UsersController : MyBaseController
{
public ChildController(UserManager<User> userManager) : base(userManager) {}
Update: The answer given here is what I want to achieve, however the question was asked for ASP.NET Core 1.0, I'm interested in whether any solutions have been added in ASP.NET Core 2.0.
Upvotes: 8
Views: 11822
Reputation: 505
In my Program.cs for my .NET 6.0 WEBAPI project I have:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers().AddControllersAsServices();
builder.Services.ScanCurrentAssembly();
Then a class
[RegisterService(ServiceLifetime.Scoped)]
public class AuthoriseByRole : AuthorizeAttribute, IAuthorizationFilter
{
...
[InjectService]
public ICurrentUser CurrentUser{ get; set; }
...
}
But CurrentUser never gets injected. Is there an obvious problem?
Upvotes: 0
Reputation: 8107
You can perform setter injection with the built-in DI container (Microsoft.Extensions.DependencyInjection) using Quickwire. Unlike Autofac, this is not a new DI container, it just extends the default one.
To make it work:
ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
// Activate controllers using the dependency injection container
services.AddControllers().AddControllersAsServices();
services.ScanCurrentAssembly();
// ...
// Register your other services
}
By default, ASP.NET Core will activate controllers by instantiating them directly without going through the DI container. Fortunately, this behaviour can easily be overridden to force ASP.NET Core to resolve controllers using dependency injection. This is what services.AddControllers().AddControllersAsServices()
does.
ScanCurrentAssembly
is necessary to get Quickwire to search for services declared in your assembly and register them (which will include your controllers).
[RegisterService]
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
This will make your ChildController
discoverable when ScanCurrentAssembly
is called in step 1.
public abstract class MyBaseController : Controller
{
[InjectService]
public UserManager<User> UserManager { get; private set; }
}
Now the UserManager
property in your child controller will be automatically set from the dependency injection container.
Upvotes: 1
Reputation: 101
You have two kind of DI
If DI is doing well, u can have unit test without injection system, if all injections are in ctor then you'll break every unit test, every time for nothing.
So all injections in ctor break open/close principle.
One more point is DI is for interface implementation or module public part, object under this implementation are initialized manually.
So setter is not bad because there are hidden by interface.
Upvotes: -1
Reputation: 4279
In general it is good advice to avoid non constructor DI as it is considered a bit of an anti pattern, there is a good discussion about it in this related question.
With the default Microsoft.Extensions.DependencyInjection container in aspnet core, the answer is no, but you could swap to something more powerfull like autofac (which has property injection) if you are sure you really need this feature.
Upvotes: 5