dependency injection vs constructor overload - c#

I am working on a .net core project where each controller has their own service as DI. All those services share some common stuff so I abstract a BaseService class:
public class BaseService
{
public BaseService(IHttpContextService srv)
{
...
}
}
This BaseService, or in another word, all the services need another service for the HTTP context.
Now I need to inherit from this BaseService if I need a new service for a new controller:
public class MyFirstService : BaseService
{
public MyFirstService(IHttpContextService srvHttp, AdditionalService srvAdditional) {}
}
In its constructor, I will need to specify the IHttpContextService again, and a few additional services this MyFirstService needs.
But this seems wrong because the child is a descendant and therefore should have the IHttpContextService naturally. Not to mention the child doesn't have a constructor with the same parameters as the ancestor which gives a compile error.
Is there a way to DI objects outside of the constructor? Or just get rid of the DI from .net core? Or I should change my design pattern?

Related

Inject one service that uses methods from multiple interfaces

I am trying to inject an instance of a service into my NameController. The service uses methods from multiple service classes, so I'm doing this with multiple interface inheritance.
With the code I provided, using _oneThreeService I am actually able to access all the methods that OneService.cs and TwoService.cs contain. However, when I run the application, I get an error that states: InvalidOperationException: Unable to resolve service for type 'ServiceClassLibrary.IOneThreeService' while attempting to activate 'Web.Controllers.NameController'.
In the ConfigureServices method, I have tried adding this line services.AddScoped<IOneThreeService, OneService, ThreeService>(); but that can't be done.
What I want is to be able to use methods from those two service classes by injecting only one service into the controller.
Startup.cs > ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IOneService, OneService>();
services.AddScoped<ITwoService, TwoService>();
services.AddScoped<IThreeService, ThreeService>();
services.AddControllersWithViews();
}
IOneThreeService.cs:
public interface IOneThreeService : IOneService, IThreeService
{
}
NameController.cs:
public class NameController : Controller
{
private readonly IOneThreeService _oneThreeService;
public NameController(IOneThreeService oneThreeService)
{
_oneThreeService = oneThreeService;
}
[HttpGet]
public IActionResult Index()
{
_oneThreeService.MethodFromOneService();
_oneThreeService.MethodFromTwoService();
return View();
}
}
It feels like you expect container to implement IOneThreeService for you based on fact the interface has no new methods and both base interfaces are registered in container - this functionality does not exist in any DI container I know, you need to register and implement such interface on your own.
Interfaces need implementation, just defining interface is not enough for compiler to find how it is implemented.
New interface also must be registered - there is no magic to find implementation of such interface.
Options:
write class that implements IOneThreeService completely and register it.
write class that takes implementations of IOneService and IThreeService, then implements IOneThreeService by forwarding calls to the corresponding service and register it (if constructor just takes interface the DI container will fill them baed on correspondingly registered base interfaces).
instead of creating the new interface you can just implement both interfaces on the same class and register same instance for both interfaces

ASP.NET Core MVC Dependency Injection via property or setter method

It has been well documented, how to inject dependencies into services.
Question: But is it (already) possible in ASP.NET Core 2.0 to have the system's DI mechanism automatically inject a service into a method or into a property?
Sidenote: In PHP-Symfony this pattern is called setter injection.
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.
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.
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:
Add this to 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).
Decorate your child controller with [RegisterService]
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
This will make your ChildController discoverable when ScanCurrentAssembly is called in step 1.
Decorate the setter
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.
You have two kind of DI
Mandatory, it's injection needed for object initialization then it's injection setted in constructor.
Optional, it's injection needed for action.
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.

Can't inject a delegate using ASP.NET Core DI

Say I've a MVC Core Controller like this:
public class SomeController
{
public SomeController(IConfiguration appConfig, Func<string> someDelegate)
{
}
}
Also, I'm using AutoFac to resolve injections. Object injections are working flawlessly while adding a delegate injection produces an ASP.NET Core exception which tells that Func<string> can't be injected because there's no component to inject with such type.
When I try to manually resolve SomeController using AutoFac I get the desired behavior.
Is there any way to support this scenario without using AutoFac to resolve controllers?
Controllers are not resolved via DI by default, they are constructed in the DefaultControllerFactory or so.
Update
Microsoft.Extensions.DependencyInjection doesn't support named components, discovery, auto registrations, decorators etc.
It's meant to be simple out of the box IoC and provide the base for DI for basic applications and offer easy way for 3rd party IoC containers (with advanced features such as auto discovery, decorators etc.) to be integrated (basically all they need is process the information in IServiceCollection and return their own implementation of IServiceProvider from Configure method).
Tag helpers, controllers and view components are different in this aspect as they have their own activators (the default one use activation utilities, which at some point further down the pipeline use the service provider). For that reasons AddControllersAsServices exists, because it replaces DefaultControllerActivator (which uses ActivationUtilities, see DefaultControllerActivator.cs) with ServiceBasedActivator (which uses IServiceProvider, see ServiceBasedControllerActivator).
Also see this related answer for details on how to resolve controllers, tag helpers and view components via DI.
var builder = services
.AddMvc()
.AddControllersAsServices() // this one for your case
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
I was just run into this issue myself so I thought I would share for future reference as I had one case where I wanted to resolve a delegate but including an additional library seemed like overkill.
Given the following defintions:
public interface ISomething { /*...*/ };
public interface ISomeService { /*...*/ }
public class SomeService : ISomeService { /*...*/ }
public class Something
{
public Something(ISomeService service, string key) { /*...*/ }
}
// I prefer using a delegate for readability but you
// don't have to use one
public delegate ISomething CreateSomething(string key);
The delegate can be registered like this:
var builder = services
.AddSingleton<ISomeService, SomeService>()
.AddTrasient<CreateSomething>(provider => key => new Something(provider.GetRequiredService<ISomeService>(), key));

Register both generic and specific implementation of an interface with ASP.NET Core DI

I've read the Armen Shimoon's article ASP.NET Core: Factory Pattern Dependency Injection and I've decided to solve my ASP.NET Core DI problem using the technique suggested by him.
I’ve got a generic interface:
public interface IItemRepository<out T> where T : BaseItem
and its generic implementation:
public class ItemRepository<T> : IItemRepository<T> where T : BaseItem
I register it with:
services.AddSingleton(typeof(IItemRepository<>), typeof(ItemRepository<>));
But for Currency I’ve got a specific implementation:
public class CurrencyRepository : ItemRepository<Currency>
(Curency is of the BaseItem type.) What I want is to register
CurrencyRepository
for
IItemRepository<Currency>
and
ItemRepository<T>
for all other items that implement BaseItem. I created a factory class to accomplish this:
public class ItemRepositoryFactory : IServiceFactory> where T : BaseItem
{
private readonly ApplicationDbContext _context;
public ItemRepositoryFactory(ApplicationDbContext context)
{
_context = context;
}
public ItemRepository Build()
{
if (typeof(T) == typeof(Currency))
return new CurrencyRepository(_context) as ItemRepository;
return new ItemRepository(_context);
}
}
but I don’t know how to register it with IServiceCollection. Or maybe I’m not on the right way at all?
You can't register it explicitly. ASP.NET Core DI is meant to be simple and offer out of box DI/IoC experience and easy for other DI/IoC containers to plugin.
So the built-in IoC doesn't offer Auto-Registrations, Assembly scanning, Decorators or registration of all interfaces/sub types of the class.
For concrete implementations, there is a "workaround"
services.AddScoped<IMyService,MyService>();
services.AddScoped<MyService>(provider => provider.GetService<IMyService>());
Then both MyService and IMyService inside a constructor would receive the same instance of the class.
But this doesn't work with open generics and is a manuell process. For automatic discovery or registration you need a 3rd party IoC container, such as Autofac, StructureMap etc.
But in your concrete sample it should be enough to register IItemRepository<Currency> inside your ConfigureServices method
services.AddScoped<IItemRepository<Currency>,CurrencyRepository>();
But actually the open generic should cover this case already, if you inject IItemRepository<Currency> into your services.

How do I control the lifetime of a custom IResourceProvider?

I've taken this approach to injecting a custom resource provider in my ASP.NET MVC application, but I'm having some problems with object lifetime management.
I'm using Castle Windsor, so I have the following implementation of the factory:
public class DefaultResourceProviderFactory : ResourceProviderFactory
{
public override IResourceProvider CreateGlobalResourceProvider(string classKey)
{
// IoC is a static helper class that gives me static access to the
// container. IoC.Resolve<T>(args...) simply calls container.Resolve<T>(args...).
return IoC.Resolve<IResourceProvider>(new { resourceType = "Global" });
}
public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
{
// resourceType
return IoC.Resolve<IResourceProvider>(new { ResourceType = virtualPath });
}
}
However, the IResourceProvider I have registered in the container doesn't seem to have its lifetime managed correctly. It has some other dependencies of its own, some of which have somewhat complicated lifestyles (per web request or per transaction), so I've registered the IResourceProvider as transient to ensure that its dependencies are always valid. But the MVC framework is stepping on my toes, keeping a reference to the IResourceProvider across web requests, which causes ObjectDisposedExceptions when its dependencies have been invalidated on the next request.
What I'd like to do, is to make the MVC framework use the factory every time it needs an instance of my IResourceProvider, and - if possible - also to invoke IoC.Release(provider) or something similar when it's done with it.
How do I micro-manage the lifestyle of the custom IResourceProvider in a way that the MVC framework will respect?
After searching around for various ways to control the lifetime of the IResourceProvider itself, I decided that it was better to refactor my implementation to utilize the Typed Factory Facility.
My IResourceProvider implementation formerly looked something like this:
public class CachedResourceProvider : IResourceProvider {
CachedResourceProvider(IResourceRecordRepository repo) { /* ... */ }
// other members...
}
Now, I changed it to this instead:
public class CachedResourceProvider : IResourceProvider {
CachedResourceProvider(IResourceRecordRepositoryFactory repo) { /* ... */ }
// other members...
}
The factory interface is a new one, defined as
public interface IResourceRecordRepositoryFactory {
IResourceRecord NewInstance();
void Release(IResourceRecord instance);
}
and every usage of the private _repo instance in the CachedResourceProvider was refactored to three statements: get a repo instance from the factory, use the repo instance to fetch/save something, release the instance through the factory.
I registered them like this:
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IResourceRecordRepositoryFactory>().AsFactory());
Now, even though MVC is keeping a reference to my resource provider across web requests, the services it uses are re-fetched from the Windsor container each time they're used, so the container is in full control of their lifetime.

Categories