ASP.Net Core从另一个控制器调用一个控制器 [英] ASP.Net Core Call a controller from another controller

查看:1945
本文介绍了ASP.Net Core从另一个控制器调用一个控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的ASP.Net Core MVC 6解决方案中,我有两组控制器.一组包含具有常规视图的网页.另一组包含API控制器.

In my ASP.Net Core MVC 6 solution I have two sets of controllers. One set contains the webpages with their regular views. Another set contains the API controllers.

为避免重复数据库逻辑,Web控制器正在使用API​​控制器.目前,我正在通过将其作为构造函数参数传递给DbContext来手动创建所需控制器的实例.这是依赖项注入为Web控制器提供的DbContext.

To avoid duplicating db logic the web controllers are using the API controllers. Currently I am creating an instance of the required controller manually by handing it a DbContext as constructor argument. This is the DbContext given to web controller by dependency injection.

但是每当我向API控制器添加另一个构造函数参数时,我都需要修改所有使用此API控制器的Web控制器.

But whenever I add another constructor parameter to the API controller I need to modify all web controllers that use this API controller.

如何使用ASP.Net 5内置的依赖项注入系统为我创建所需的API控制器的实例?然后它将自动填写所需的构造函数参数.

How can I use the dependency injection system builtin to ASP.Net 5 to create an instance of the required API controller for me? Then it would fill in the required constructor parameters automatically.

一种解决方案是将db逻辑从API控制器移动到单独的层,然后从API和Web控制器调用该逻辑.这不会解决我的问题,因为新层仍然需要相同的参数,而且我不喜欢不必要的接线.

One solution could be to move the db logic from the API controllers to a separate layer and call that from both API and web controllers. This would not solve my problem since the new layer would still need the same parameters and I'm not fan of the unnecessary wiring.

另一种解决方案是让网络控制器通过网络调用访问API,但这只会增加应用程序的复杂性.

Another solution would be to have the web controllers access the API through a web call, but that just adds complexity to the app.

今天我正在这样做:

public IActionResult Index()
{
    using (var foobarController = new Areas.Api.Controllers.FoobarController(
        // All of these has to be in the constructor of this controller so they can be passed on to the ctor of api controller
        _dbContext, _appEnvironment, 
        _userManager, _roleManager, 
        _emailSender, _smsSender))
    {
        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);
    }
}

我希望有这样的东西: (此示例不起作用.)

And I am hoping for something like this: (This example does not work.)

using (var foobarController = CallContextServiceLocator.Locator.ServiceProvider.GetService<Areas.Api.Controllers.FoobarController>())
{
    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);
}

推荐答案

为了能够使用另一个控制器中的一个控制器,您需要:

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

  1. 在Startup.cs ConfigureServices中注册控制器:services.AddTransient <Areas.Api.Controllers.FoobarController, Areas.Api.Controllers.FoobarController>();
  2. 您必须将要访问的控制器作为ctor参数传递到主控制器中.

如果您需要访问控制器中的本地属性(例如UserUrl),可以通过两种方法进行.

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

第一种方法是使用DI获取IHttpContextAccessor的实例来访问UserIUrlHelper的实例来访问Url对象:

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.

这篇关于ASP.Net Core从另一个控制器调用一个控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆