ASP.Net Core Call a controller from another controller

@B12Toaster is correct for MVC but if you only use ApiController you should do it like this:

services.AddControllers().AddControllersAsServices();

To be able to use a controller from another controller you need to:

  1. Register the controller in Startup.cs ConfigureServices: services.AddTransient <Areas.Api.Controllers.FoobarController, Areas.Api.Controllers.FoobarController>();
  2. You must pass the controller you want to access as a ctor parameter into the main controller.

If you need to access local properties in the controller such as User or Url there are two ways to do this.

The first way is to use DI to get an instance of IHttpContextAccessor to access User and IUrlHelper to access Url objects:

public class FoobarController : Controller
{
    private readonly ApplicationDbContext _dbContext;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IUrlHelper _urlHelper;
    public FoobarController(ApplicationDbContext dbContext, IHttpContextAccessor httpContextAccessor, IUrlHelper _urlHelper, [...])
    {
         _dbContext = dbContext;
         _httpContextAccessor = httpContextAccessor;
         _urlHelper = urlHelper;
    }

    public FoobarResponse List(FoobarRequest request)
    {
        var userId = _httpContextAccessor.HttpContext.User.GetUserId();
        var response = new FoobarResponse();
        response.List = _dbContext.Foobars.Where(f => f.UserId == userId).ToList();
        response.Thumb = 
        return response;
    }
}

The second way is to set it in the calling controller:

public class HomeController : Controller
{
    private Areas.Api.Controllers.FoobarController _foobarController;
    public HomeController(Areas.Api.Controllers.FoobarController foobarController)
    {
        _foobarController = foobarController;
    }

    private void InitControllers()
    {
        // We can't set this at Ctor because we don't have our local copy yet
        // Access to Url 
        _foobarController.Url = Url;
        // Access to User
        _foobarController.ActionContext = ActionContext;
        // For more references see https://github.com/aspnet/Mvc/blob/6.0.0-rc1/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs
        // Note: This will change in RC2
    }

    public IActionResult Index()
    {
        InitControllers();

        var model = new IndexViewModel();
        model.Foo = _foobarController.List(new FoobarRequest() { Foo = true, Bar = false });
        model.Bar = _foobarController.List(new FoobarRequest() { Foo = false, Bar = true });
        return View(model);
    }
}

The source code for ASP.Net Core MVC6 RC1 Controller can be found here. It is however undergoing heavy rewrite for RC2 and with it the properties that has to be copied to get access to User and Url will change.


How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me?

In your Startup.cs can tell the MVC to register all your controllers as services.

services.AddMvc().AddControllersAsServices();

Then you can simply inject the desired controller in your other controller via the DI mechanism and invoke its action method.


Don't do it. Move that logic to another component that gets shared between the 2 controllers. The controller is dispatched to by the framework as a result of an HTTP call, its not your public API surface. In general, your controllers should be used as a the place where the HTTP request is transformed into business objects. Operations on those objects should be delegate to another layer (especially if it needs to be used from more than one place in your application).