使用统一容器将对象注入控制器的构造函数

Inject object to the constructor of controller using unity container

我找不到任何类似的问题,所以我写这篇文章 post。有一个带有私有字段 IBaseClass 的示例控制器。示例代码如下所示:

public class TmpController : Controller
    {
        private IBaseClass _baseClass;

        public TmpController()
        {
            _baseClass = new BaseClass(this);
        }   
    }

    public interface IBaseClass
    {
        //...
    }

    public class BaseClass : IBaseClass
    {
        protected TmpController TmpController;

        public BaseClass(TmpController tmpController)
        {
            TmpController = tmpController;
        }

        //IBaseClass implementation
    }

我的问题是;如何使用 Unity 框架将 BaseClass 对象注入到 TmpController 的构造函数中? 我想让我的控制器 "slimmer"。我想将有关验证和准备我的控件(如 comboBox 等)的数据源的逻辑放到不同的 class。在那个非常具体的案例中,我尝试在我的 .Web 项目中制作某种 SOC,这将使我的控制器更易于阅读和维护。我在每个视图中使用一个控制器的方法,但我遇到了非常复杂的情况。目前我有超过 3000 行代码的控制器并且很难维护所以我想用它做点什么。 是的,我正在使用服务和存储库,但问题是关于 ViewModel 的验证、将 ViewModel 对象映射到 DTO 和向后映射、准备给定组件的数据源等。

@Razem,你从我的评论中猜到的是正确的。并且您描述的负点也是有效的。

你问的"Service depending on the controller"当然可以实现,但那将是一个糟糕的设计。

目前 BaseClass 仅依赖于 TempController。当您在其他一些控制器中也需要 BaseClass 时,您将如何处理这种情况?代码将开始中断,您最终将向 BaseClass 添加新的依赖项。

此外,根据设计建议,顶层应依赖于底层,反之亦然。

话虽如此,您仍然可以通过使控制器依赖于 IBaseClass 来实现您正在寻找的功能。

我不确定您需要访问内部控制器的具体原因BaseClass。我在创建以下建议时做出了某些假设。其中一个假设是 BaseClassIBaseClassController 类 是同一程序集的一部分。

//Have a BaseController Class with the properties and/or method which you will be using in the `BaseClass` class and make them virtual so that derived controller classes can override them to have specific implementation.

public class BaseController : Controller
{
    public virtual string ControllerMethod()
    {
        return "Controller Method from Base Controller";
    }

    public virtual string RandomValue
    {
        get
        {
            return "Random value from Base Controller";
        }
    }
}

IBaseClass 中创建一个方法,它将为其设置控制器。

public interface IBaseClass
{
    void SetController(BaseController controller);

    void Method1();
}

public class BaseClass : IBaseClass
{
    private BaseController controller;
    public void SetController(BaseController controller)
    {
        this.controller = controller;
    }

    public void Method1()
    {
        var str = this.controller.RandomValue;
    }
}

并从 BaseController 派生 TempController 并使其依赖于 IBaseClass。并在 TempController 的构造函数中通过传递 this 参数来调用 IBaseClassSetController 方法。您也可以在此处覆盖 BaseController 的 method/properties。

在此之后,您可以调用 IBaseClass 的任何方法,而无需将控制器实例传递给它。

public class TempController : BaseController
{
    private IBaseClass baseClass;
    public HomeController(IBaseClass productService)
    {
        this.baseClass = productService;
        this.baseClass.SetController(this);
    }

    public override string RandomValue
    {
        get
        {
            return "Random value from Derived Class.";
        }
    }

    public ActionResult Index()
    {
        this.baseClass.Method1();

        ViewBag.Title = "Home Page";

        return View();
    }
}

在您的 Web 项目中安装 nuget 包 Unit.Mvc。打开位于 App_Start 文件夹下的文件 Unity.Config 并更改方法 RegisterTypes 如下。

public static void RegisterTypes(IUnityContainer container)
{
   container.RegisterType<IBaseClass, BaseClass>(new PerRequestLifetimeManager());
}

我相信我不需要解释这是如何工作的。

P.S。 : 您需要确保在控制器构造函数中调用 IBaseClass.SetController 方法以避免在 BaseClass 中使用控制器时出现 NullReferenceException。这是实现良好且可维护的设计所需的很小的开销。