Use Inversion of Control to construct dependency with caller - c#

Given the following ASP.NET Core controller :
public class MyController : Controller {
public MyController(IDependency dependency) { this.dependency = dependency; }
}
public interface IDependency;
public class DependencyImplementation : IDependency {
public DependencyImplementation(Controller controller) { ... }
}
I want MyController to have a new instance of DependencyImplementation injected, constructed with the controller it's being passed to. Ideally using Ninject.
The non-IoC version would be:
public class MyController : Controller {
public MyController() { this.dependency = new DependencyImplementation(this); }
}

This would cause circular dependency. Only idea I have is to introduce factory:
public interface IDependencyFactory
{
IDependency Create(Controller controller);
}
public class MyController : Controller
{
private IDependency dependency;
public MyController(IDependencyFactory dependencyFactory)
{
this.dependency = dependencyFactory.Create(this);
}
}
var kernel = new StandardKernel();
kernel.Bind<Controller>().To<MyController>();
kernel.Bind<IDependency>().To<DependencyImplementation>();
kernel.Bind<IDependencyFactory>().ToFactory();
var controller = kernel.Get<Controller>();
Or maybe rather reconsider whole design.

Related

ASP.NET Core dependency injection - How to create instances?

In Startup:
services.AddTransient<IMyService, MyService>()
Controller method:
[HttpGet]
public JsonResult GetSomething()
{
Helper helper = new Helper(new MyService()); // works but looking better solution
return Ok("");
}
Helper class:
public class Helper
{
private readonly IMyService myService;
public Helper(IMyService myService)
{
this.myService = myService;
}
public Helper()
{
this.myService = ?;
}
}
I want to instantiate Helper class without inject the dependency manually with new MyService().
The MyService() class should be the class in startup.
I also want to place the the Helper class in another assembly.
I see some code with
var service = (IFooService)serviceProvider.GetService(typeof(IMyService));
but i don't know how to get a serviceProvider instance without injecting it to the helper.
Add the helper to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<Helper>(sp => new Helper(sp.GetRequiredService<IMyService>()));
And explicitly inject it into the controller
public class MyController: Controller {
private readonly Helper helper;
public MyController(Helper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
Ideally the helper should be derived from an abstraction as well
public class Helper : IHelper {
private readonly IMyService myService;
public Helper(IMyService myService) {
this.myService = myService;
}
//...
}
And added accordingly to the container
services.AddTransient<IMyService, MyService>()
services.AddScoped<IHelper, Helper>();
to avoid the controller having tight coupling to concretions (implementation concerns).
public class MyController: Controller {
private readonly IHelper helper;
public MyController(IHelper helper) {
this.helper = helper;
}
[HttpGet]
public JsonResult GetSomething() {
//...use helper
return Ok("");
}
//...
}
A way to properly resolve the service via DI:
[HttpGet]
public JsonResult GetSomething([FromServices] IMyService myService)
{
Helper helper = new Helper(myService);
return Ok("");
}
Or you inject it via ctor and use it in the method.

Decorator pattern using Castle Windsor when different class need to be injected depending on caller

I want to use decorator pattern using Castle Windsor to create view model for my api, but having different classes injected into decorators depending on controller. I have two versions of api endpoint.
One for HomeV1Controller:
public class HomeV1Controller : ApiController {
private readonly IHomeViewModelFactory _factory;
public HomeV1Controller(IHomeViewModelFactory factory) {
_factory = factory;
}
}
and second:
public class HomeV2Controller : ApiController {
private readonly IHomeViewModelFactory _factory;
public HomeV2Controller(IHomeViewModelFactory factory) {
_factory = factory;
}
}
both controllers accepts IHomeViewModelFactory which it definitions is:
public interface IHomeViewModelFactory {
HomeViewModel CreateViewModel();
}
now I would like to inject common view model factory for both controllers and that factory need to call next view model factory which is specific for controller. So I have a factories:
Common:
public class UserViewModelFactory : IHomeViewModelFactory {
private readonly IHomeViewModelFactory _factory;
public UserViewModelFactory(IHomeViewModelFactory factory) {
_factory = factory;
}
public HomeViewModel CreateViewModel() {
var vm = _factory.CreateViewModel();
vm.User = new User();
return vm;
}
}
and two specific for controller:
public class HomeV1ViewModelFactory : IHomeViewModelFactory {
public HomeViewModel CreateViewModel() {
// logic only for V1 to create vm
var vm = new HomeViewModel {
Articles = new Articles()
};
return vm;
}
}
public class HomeV2ViewModelFactory: IHomeViewModelFactory {
public HomeViewModel CreateViewModel() {
// logic only for V2 to create vm
var vm = new HomeViewModel {
Issues = new Issues()
};
return vm;
}
}
Now the HomeV1Controller needs to have injected UserViewModelFactory which has dependency of HomeV1ViewModelFactory and HomeV2Controller needs to have injected UserViewModelFactory which has dependency of HomeV2ViewModelFactory.
Only thing I can think of is service override:
container.Register(Component.For<HomeV1Controller>()
.DependsOn(Property.ForKey<IHomeViewModelFactory>().Is("UserViewModelFactory1")));
container.Register(Component.For<HomeV2Controller>()
.DependsOn(Property.ForKey<IHomeViewModelFactory>().Is("UserViewModelFactory2")));
container.Register(Component.For<IHomeViewModelFactory>()
.ImplementedBy<UserViewModelFactory>()
.Named("UserViewModelFactory1")
.DependsOn(Property.ForKey<IHomeViewModelFactory>().Is("HomeV1ViewModelFactory")));
container.Register(Component.For<IHomeViewModelFactory>()
.ImplementedBy<UserViewModelFactory>()
.Named("UserViewModelFactory2")
.DependsOn(Property.ForKey<IHomeViewModelFactory>().Is("HomeV2ViewModelFactory")));
container.Register(Component.For<IHomeViewModelFactory>().ImplementedBy<HomeV1ViewModelFactory>().Named("HomeV1ViewModelFactory"));
container.Register(Component.For<IHomeViewModelFactory>().ImplementedBy<HomeV2ViewModelFactory>().Named("HomeV2ViewModelFactory"));

BaseController's overloaded constructor not being executed?

public class BaseController : Controller
{
[Inject]
public IUnitOfWork UnitOfWork { get; set; }
private readonly ISomeService _someService ;
public BaseController(ISomeService someService)
{
_someService = someService;
}
public void Contacts()
{
contacts = _someService .GetById(1);
ViewBag.someThing = contacts; //Add whatever
}
public BaseController()
{
}
}
While I'm sending someService in the :base I can get the data from it. However I don't want to send someService from each controller like AboutController to the BaseController and to write too much code.
public class HomeController : BaseController
{
private readonly ISomeService someService;
public HomeController(ISomeService someService) : base(someService)
{
_someService = someService;
}
}
public class AboutController : BaseController
{
private readonly IAboutService _aboutService;
public AboutController (IAboutService aboutService)
{
_aboutService = aboutService;
}
}
So in AboutController view still i wanna get someService's data without sending parameter to the BaseController
The short answer would be separated in two cases:
If you want to use ISomeService from the base controller you are obliged to pass that service through base constructor like this:
public class AboutController : BaseController
{
private readonly IAboutService _aboutService;
public AboutController (IAboutService aboutService, ISomeService someService) : base(someService)
{
_aboutService = aboutService;
}
}
If you dont want to use that service you use the default base constructor like this otherwise it will be null if you try to access it:
public class AboutController : BaseController
{
private readonly IAboutService _aboutService;
public AboutController (IAboutService aboutService) : base()
{
_aboutService = aboutService;
}
}
You are in the first scenario so you need to pass it through the constructor in order to initialize it!
But if you like to break the pattern you would choose other ways of injecting the services into your base controller:
First one by using auto-properties:
For example:
public ISomeService SomeService { get; set;}
Another way is to get the instance of the service by using DependecyResolver but this would 'break' somehow the DI pattern and it will make harder for testing etc. But if you choose to do so here is the code for that:
public class BaseController : Controller
{
[Inject]
public IUnitOfWork UnitOfWork { get; set; }
private readonly ISomeService _someService ;
public BaseController(ISomeService someService)
{
_someService = someService;
}
public void Contacts()
{
contacts = _someService .GetById(1);
ViewBag.someThing = contacts; //Add whatever
}
public BaseController()
{
_someService = DependencyResolver.Current.GetService<ISomeService >();
}
}
For more info refer to this question here

Using inheritance and dependency injection at the same time

Here is how my application makes a call to the database:
Web App -> Business Layer -> Data Layer
Everything is using dependency injection.
For example:
In the controller in my Web app I make a call like this:
await _manager.GetCustomers();
Which goes into my Business Layer:
public class CustomerManager : ICustomerManager
{
private ICustomerRepo _repository;
public CustomerManager(ICustomerRepo repository)
{
_repository = repository;
}
public Task<IList<Customer>> GetCustomers(string name = null)
{
return _repository.GetCustomers(name);
}
}
Which goes into my Data Layer:
public class CustomerRepo : BaseRepo, ICustomerRepo
{
public CustomerRepo(IConfigurationRoot configRoot)
: base(configRoot)
{
}
public Customer Find(int id)
{
using (var connection = GetOpenConnection())
{
...
}
}
}
The trick here is that CustomerRepo inherits from BaseRepo to be able to use the GetOpenConnection() function. But at the same time BaseRepo needs an IConfigurationRoot injected into it from the web application. How can I do both?
public class BaseRepo
{
private readonly IConfigurationRoot config;
public BaseRepo(IConfigurationRoot config)
{
this.config = config;
}
public SqlConnection GetOpenConnection(bool mars = false)
{
string cs = config.GetSection("Data:DefaultConnection:ConnectionString").ToString();
...
}
}
How would you instantiate (or even compile) a CustomerRepo at all, regardless of dependency injection? You need an IConfigurationRoot parameter to pass through to the base constructor. Like:
public CustomerRepo(IConfigurationRoot configRoot)
: base(configRoot)
{
}
See https://msdn.microsoft.com/en-us/library/hfw7t1ce.aspx for info on the base keyword.

instantiates class using ninject ioc in .net

I am using Ninject to do some IoC in my ASP.NET MVC application.
I have an interface "IService.cs" :
public interface IService
{
string method();
}
I have the corresponding implementation "Service.cs" :
public class Service
{
string method()
{
return "result";
}
}
I have done the binding in another class heriting from NinjectModule :
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
RegisterServices();
}
private void RegisterServices()
{
Kernel.Bind<IService>().To<Service>();
}
}
I have my class A which use this service :
public class A
{
private readonly IService _service;
private int i;
public A(IService service, int i)
{
this._service=service;
this.i=i;
}
}
The problem is that now, I don't know how to instantiate my class A in my application. This is where am I stuck, how can I call Ninject
to tell my app to go get the implementation of my interface:
var myClass=new A(????)
The main problem is that your Service class does not implement IService.
public class Service
{
string method()
{
return "result";
}
}
It should be
public class Service : IService
{
public string method()
{
return "result";
}
}
But as for instantiating a class, the best approach is to use a composition root to build an object graph. In MVC, that is best handled by implementing IControllerFactory.
public class NinjectControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public NinjectControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null
? null
: (IController)this.kernel.Get(controllerType);
}
}
Usage
using System;
using Ninject;
using DI;
using DI.Ninject;
using DI.Ninject.Modules;
internal class CompositionRoot
{
public static void Compose()
{
// Create the DI container
var container = new StandardKernel();
// Setup configuration of DI
container.Load(new MyNinjectModule());
// Register our ControllerFactory with MVC
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(container));
}
}
In Application_Start, add:
CompositionRoot.Compose();
You will also need to create an interface for your class A and register it. An integer cannot be resolved automatically, you have to do that explicitly.
Kernel.Bind<IClassA>().To<A>()
.WithConstructorArgument("i", 12345);
And then you would add your dependency to a controller. Dependencies of dependencies are resolved automatically.
public class HomeController : Controller
{
private readonly IClassA classA;
public HomeController(IClassA classA)
{
if (classA == null)
throw new ArgumentNullException("classA");
this.classA = classA;
}
public ActionResult Index()
{
// Use this.classA here...
// IService will be automatically injected to it.
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
}

Categories

Resources