Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection when controller called from another controller

I have a single ASP.NET 5.0 (vnext) project where I am implementing both a Web Api and an Mvc front end. I want my Mvc controller to call the Web Api controller, which is working just fine. I built the api based on the example at http://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6, and it is working great. The Mvc front end can call the WebApi controller successfully, but the ITodoRepository doesn't get provided by the dependency injection framework when I instantiate it from the Mvc controller.

public class Startup
{
    public void Configure(IApplicationBuilder app, ILoggerFactory logFactory)
    {
        ...
        app.UseServices(services =>
        {
            services.AddSingleton<ITodoRepository, TodoRepository>();
        });
        ...

[Route("api/[controller]")]
public class TodoController : Controller
{
    /* The ITodoRepository gets created and injected, but only when the class is activated by Mvc */
    TodoController(ITodoRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public IEnumerable<TodoItem> Get()
    {
        return _repository.AllItems;
    }
    ...

public class HomeController : Controller
{
    public IActionResult Index()
    {
        var tc = new TodoController(/* have to create my own ITodoRepository here */);
        return View(tc.Get());
    }
    ...

I was able to add an ITodoRepository to the HomeController with the [Activate] attribute, and then pass that to the constructor for the TodoController, but that doesn't pass the smell test to me. Home Controller shouldn't have to have or even know about those.

Is there another way to create the TodoController instance that will invoke the DI logic and provide the dependencies?

like image 802
lordjeb Avatar asked Jan 12 '15 00:01

lordjeb


People also ask

What are the methods of dependency injection into Controllers in core?

Dependency injection into controllers in ASP.NET Core 1 Constructor Injection. Services are added as a constructor parameter, and the runtime resolves the service from the... 2 Action injection with FromServices. 3 Access settings from a controller. Accessing app or configuration settings from within a controller is a common pattern. More ...

What is dependency injection in Java?

A container or an object which creates and passes the dependant object in an application is called Dependency Injection. In simple words instead of creating dependant objects manually by a programmer, objects are get created by library container which normally handles both the creation and garbage handling.

How to inject a controller into another controller in MVC?

In your Startup.cs can tell the MVC to register all your controllers as services. Then you can simply inject the desired controller in your other controller via the DI mechanism and invoke its action method. Show activity on this post.

What is dynamic dependency injection in ASP NET Core?

Dependency injection is a technique that follows the Dependency Inversion Principle, allowing for applications to be composed of loosely coupled modules. ASP.NET Core has built-in support for dependency injection, which makes applications easier to test and maintain.


2 Answers

If you're concerned about code smell, the main concern should be about having one controller calling another controller.

Controllers are meant to be called in two scenarios:

  1. By the system (i.e. MVC)
  2. By your unit tests

Instead, I recommend having both controllers call a business logic component that itself might use dependency injection to acquire its dependencies, and that each controller perhaps use dependency injection to acquire the business logic dependency as well.

public class HomeController : Controller {
    public HomeController(IMyAppBusinessLogic bll) { ... }
}

public class WebApiController : Controller {
    public WebApiController(IMyAppBusinessLogic bll) { ... }
}

public class MyAppBusinessLogic : IMyAppBusinessLogic {
    public MyAppBusinessLogic(ITodoRepository repository) { ... }
}
like image 75
Eilon Avatar answered Oct 12 '22 23:10

Eilon


Any middleware registered using app.UseServices are available only within the scope of a web request. There is no web request context when you are trying to instantiate the webapi controller directly from your MVC app and therefore the dependencies will not be resolved.

It's normal to create an execution context manually for the purposes of unit testing. Not sure which DI framework are you using but I do something like the following in my project (OWIN not vNext) which is using SimpleInjector

public static void UseInjector(this IAppBuilder app, Container container)
{
    // Create an OWIN middleware to create an execution context scope
    app.Use(async (context, next) =>
    {
        using (var scope = container.BeginExecutionContextScope())
        {
            await next.Invoke();
        }
    });            
}
like image 40
su8898 Avatar answered Oct 12 '22 23:10

su8898