代码之家  ›  专栏  ›  技术社区  ›  Garry Shutler

优雅地减少ASP.NET MVC控制器中的依赖项数量

  •  5
  • Garry Shutler  · 技术社区  · 17 年前

    每个控制器都有5个或更多依赖项,其中一些依赖项仅用于控制器上的1个操作方法,但显然是为控制器的每个实例创建的。

    我正在努力想一个好办法来减少90%的调用不必要地创建的对象数量。

    以下是我正在玩弄的一些想法:

    1. 将控制器拆分为更小、更有针对性的控制器。
      • 目前,我们每个域实体大约有一个控制器,这导致了我们想要模拟的漂亮的URL,这意味着我们最终将得到一个更复杂的路由方案。
    2. 传入包装IoC容器的接口。
      • 这意味着只有在明确需要对象时才会创建它们。然而,这就像是在猪身上涂口红。
    3. 以某种方式扩展框架以实现两者的疯狂结合。

    4 回复  |  直到 10 年前
        1
  •  3
  •   Garry Shutler    17 年前

    我一直在思考这个问题的解决方案,这就是我想到的:

    将依赖项直接注入控制器操作,而不是注入控制器构造函数。这样你只需要注射你需要的东西。

    在global.asax中:

    protected void Application_Start()
    {
        ControllerBuilder.Current.SetControllerFactory(
                new StructureMapControllerFactory());
    }
    

    以下是structuremapcontrollerfactory:

    public class StructureMapControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(Type controllerType)
        {
            try
            {
                var controller = 
                        ObjectFactory.GetInstance(controllerType) as Controller;
                controller.ActionInvoker = 
                        new StructureMapControllerActionInvoker();
                return controller;
            }
            catch (StructureMapException)
            {
                System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
                throw;
    
            }
        }
    }
    

    和structuremapcontrolleractioninvoker(可能需要更智能一点)

    public class StructureMapControllerActionInvoker : ControllerActionInvoker
    {
        protected override object GetParameterValue(
                ControllerContext controllerContext, 
                ParameterDescriptor parameterDescriptor)
        {
            object parameterValue;
            try
            {
                parameterValue = base.GetParameterValue(
                        controllerContext, parameterDescriptor);
            }
            catch (Exception e)
            {
                parameterValue = 
                        ObjectFactory.TryGetInstance(
                                parameterDescriptor.ParameterType);
                if (parameterValue == null)
                    throw e;
            }
            return parameterValue;
        }
    }
    
        2
  •  1
  •   Denis Troller    17 年前

    有一个“服务定位器”的概念已经被添加到类似Prism的作品中。它的优点是减少了开销。

    也许把一些工作委托给你会更好。如果您打算以某种方式重新划分控制器,那么您可能只想创建该类,并使控制器通过DI获得该类的实例。

        3
  •  1
  •   Craig Stuntz    17 年前

    我会单独考虑这个问题。 依赖对象的创建 . 依赖性只是控制器源代码引用某个类型这一事实。这在代码复杂度方面有一定的成本,但运行时成本不值得一提。另一方面,对象的实例化有运行时成本。

    减少代码依赖项数量的唯一方法是分解控制器。正如您所说,任何其他方法都只是让依赖项变得更漂亮。但是,使依赖关系(与依赖对象的实例化相反,我将在第二节中介绍)变得更漂亮可能是一个解决方案,您不需要分解控制器。因此,我认为国际奥委会是一个不错的解决方案。

    真实的 问题,而不是依赖性, 本质上 . 因为随着项目的扩大,情况只会变得更糟。您可以通过更改对象的实例化来解决此问题,以便在需要对象之前不会发生此问题。一种方法是在惰性实例化中使用属性。另一种方法是使用动作方法的参数和实例化所需对象的模型绑定。另一种方法是编写返回所需实例的函数。如果不知道所使用对象的用途,很难说哪种方式最好。

        4
  •  1
  •   mhamrah    17 年前

    您的控制器可能变得太“胖”。我建议创建一个位于控制器下面的应用层。应用层可以封装控制器操作中进行的大量编排,并且更易于测试。它还将帮助您在不受指定操作方法约束的情况下组织代码。

    使用ServiceLocation也会有所帮助(是的,我基本上是在重申Denis Troller的答案——这可能不太好,但我确实对他的答案投了赞成票)。

    推荐文章