MVC中的IoC:如何处理从控制器到模型的服务对象流?

时间:2012-09-28 15:35:13

标签: asp.net-mvc asp.net-mvc-3 dependency-injection inversion-of-control

我正在使用MVC3并实现了IoC,通过构造函数参数向控制器提供服务/管理器对象。反过来,这些可能会传递给模型。

我遇到的问题是将这些对象传遍整个地方可能会很麻烦。

示例:

public CartController(
        ICartManager cartManager,
        IProductManager productManager,
        IUpsellManager upsellManager,
        IAccountManager accountManager,
        ... more ...)
    {
        ... store to class variables ...
    }

    public ActionResult Index()
    {
        ...

        CartModel model = new CartModel(
            cartManager, 
            accountManager, 
            upsellManager, 
            productManager, 
            ... );

        return View(model);
    }

购物车模型可能包含必须传递参数的子模型。如你所见,一切都变得非常麻烦。我准备好了,如果你有这么多的构造函数参数,你的控制器可能做得太多,但这是一个复杂的页面,并且该站点将包含许多其他复杂的页面。我不想传递这么多东西,但我怎么能不传递它们并维持控制呢?

我很想在模型中使用DependencyResolver,但这会破坏目的,而服务定位器就是已知的反模式。

如何在不放弃IoC的好处的情况下避免传递这么多论点?

3 个答案:

答案 0 :(得分:3)

使用依赖性反转的优点是在应用程序中的各种角色之间强制明确分离职责。 Controller真的只对处理HTTP请求和HTTP响应感兴趣。所有其他逻辑都在其他地方处理,控制器委托它依赖于执行此工作的类型。然后对系统中的每个功能重复该模式。检测不遵循此模式的一种方法是使用new运算符创建类型并将依赖项传递给构造函数。这是您正在使用的IoC容器的工作。

我建议交换逻辑并让CartManager为视图返回一个CartModel。这可能是某种特定于视图的DTO。如何将数据放入此对象是CartManager的责任。如果它需要使用其他服务,可以将它们注入到它的构造函数中。

public CartController : Controller

private ICartManager _cartManager;

public CartController(ICartManager cartManager) {
     _cartManager = cartManager;
}


[HttpGet]
public ActionResult Index(int userId) {
    var model = _cartManager.CreateCart(int userId);
    return View(model);
}

...

public class CartManager : ICartManager {

   IDbService _dbService;

   public CartManager(IDbService dbService){

       _dbService = dbSerivce;
   }

   CartModel CreateCart(int userId) {

      var user = _dbService.FindTheUser(int user);
      var cartModel = new CartModel { userId = userId, Name = user.Name };
      /* other stuff to map up a cartmodel 

      return cartModel;
   }
}

这个想法不只是特定于IoC容器的使用,而且也是创建MVC应用程序的好习惯。我还发现Rob Ashton的这个post是一个很好的指南。

答案 1 :(得分:1)

我喜欢在这个场景中使用工厂模式,你需要在A类(CartController)中实例化B类(CartModel),并且B中有一堆A不需要的依赖项。

public CartController(
    ICartModelFactory factory
    ... more ...)
{
    ... store to class variables ...
}

public ActionResult Index()
{
    ...

    CartModel model = factory.GetInstance(
        ... );

    return View(model);
}

答案 2 :(得分:1)

您不应该将所有这些服务传递给您的视图。这意味着您的模板现在必须执行调用此数据的操作,这会使事情变得复杂(如您所见)。除了不必要的复杂性之外,它还在视图中创建这些服务的依赖关系,并将视图与这些服务紧密耦合。如果更改服务,则必须更改使用它的所有视图。

您需要做的第一件事是创建一个ViewModel,其中包含视图所需的所有数据。然后,您需要找到一种方法将经理类返回的数据映射到此视图中。您可以在控制器中手动执行此操作,也可以使用AutoMapper之类的功能进行翻译。

另一个选择是重构ICartManager以便它返回所有数据(然后你的CartManager类会有构造函数注入其他服务)或创建一个聚合它们的不同服务并构造一个可以映射到View的对象模型。

你永远不必传递这些方法。应始终将它们注入物体中。