【问题标题】:Inject object to the constructor of controller using unity container使用统一容器将对象注入控制器的构造函数
【发布时间】:2017-08-01 09:57:00
【问题描述】:

我找不到任何类似的问题,所以我正在写这篇文章。有带有私有字段 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 的构造函数? 我想让我的控制器“更苗条”。我想将关于验证和准备我的控件(如组合框等)的数据源的逻辑放到不同的类中。在那种非常特殊的情况下,我尝试在我的 .Web 项目中制作某种 SOC,这将使我的控制器更易于阅读和维护。我正在使用每个视图一个控制器的方法,但我遇到的情况非常复杂。目前我有超过 3000 行代码的控制器,而且很难维护,所以我想用它做点什么。 是的,我正在使用服务和存储库,但问题在于 ViewModel 的验证、将 ViewModel 对象映射到 DTO 和向后映射、准备给定组件的数据源等。

【问题讨论】:

  • 你的构造函数在这里搞错了。您需要将IBaseClass 注入TmpController,而不是相反。
  • #Daniel Corzo 我认为你错了。该链接通常是关于 c# case 而不是 asp.net mvc,它是关于不同的问题“指定要使用的 Unity IoC 容器的构造函数”
  • DavidG 没有那么简单,因为 BaseClass(TmpController tmpController) 构造函数。
  • @RazemPonad-kilo 是的,这就是我的意思,你真的认为这是个好主意吗?我当然不会。

标签: c# asp.net-mvc unity-container


【解决方案1】:

@Razem,您从我的评论中猜测是正确的。你描述的减号也是有效的。

您所要求的“服务取决于控制器”肯定可以实现,但那将是一个糟糕的设计。

目前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 的方法/属性。

在此之后,您可以调用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());
}

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 2021-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    相关资源
    最近更新 更多