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

Gar*_*ler 5 asp.net-mvc dependencies dependency-injection inversion-of-control

我们正在开发正在成为一个相当大的ASP.NET MVC项目,并且代码气味开始抬头.

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

我正在努力想出一种减少90%的呼叫不必要地创建的对象数量的好方法.

以下是我正在考虑的一些想法:

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

我觉得别人一定遇到过同样的问题; 所以你是如何解决这个问题的,或者你是否只是忍受它,因为它在你眼中并不是那么大的问题?

And*_*ock 3

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

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

我实际上只是想出了这个,所以它有点天真,没有在愤怒中进行测试,但我打算尽快实施这个来尝试一下。欢迎提出建议!

它当然是 StructureMap 特定的,但您可以轻松使用不同的容器。

在全局.asax中:

protected void Application_Start()
{
    ControllerBuilder.Current.SetControllerFactory(
            new StructureMapControllerFactory());
}
Run Code Online (Sandbox Code Playgroud)

这是结构图控制器工厂:

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;

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和 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;
    }
}
Run Code Online (Sandbox Code Playgroud)