1

我正在使用 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 好处的情况下避免传递这么多参数?

4

3 回答 3

3

使用依赖倒置的优点是在应用程序中的各种角色之间强制执行明确的职责分离。控制器实际上只对处理 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 的这篇文章是一个很好的指南。

于 2012-09-28T16:01:06.707 回答
1

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

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

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

您永远不必传递这些方法。它们应该始终注入到对象中。

于 2012-09-28T16:47:56.927 回答
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);
}
于 2012-09-28T16:09:19.073 回答