DI构造函数注入整洁

时间:2017-07-07 08:39:34

标签: c# asp.net-mvc dependency-injection ninject

好的,我正在寻找有关依赖注入以及如何使用它的一些特定提示。

基本上我有一个使用Ninject(和Ninject MVC包)的MVC网站。因此,当我创建MVC页面时,我在控制器中使用构造函数注入。这没关系,但IMO有点'难看',但我不喜欢的主要事情是必须将所有注入的存储库传递到其他类中,它似乎有点OTT必须通过6个存储库-8存储库进入静态方法或对象构造函数。

更不用说在我的一些页面上我几乎每个存储库都要工作,因此控制器构成器变得庞大而且不是最容易管理的。

还有其他选项不会让我的代码混乱吗?我真的不想将它们作为单个“设置”对象传递,因为它只是将问题移动到不同的代码行。

我也使用相同的类库来控制台/桌面应用程序。我喜欢在类库中使用DependencyResolver.Current的想法,但是每个人都说这是一个反模式,应该使用构造函数注入。

也许有一个MyProjectDIContext类,它有一个字典,我可以在控制器构造函数中填充注入的类型,然后根据需要将上下文传递给所有方法?

我已经找到了答案,我似乎找不到合适的东西。

3 个答案:

答案 0 :(得分:2)

构造函数注入的一个好处是它使设计和可维护性问题更加明显。使用构造函数注入时,很容易看到类具有的依赖项数量,而没有构造函数注入,类仍然具有相同数量的依赖项,但它们被隐藏起来。

您看到的问题称为Constructor Over-injection并且它具有设计气味,因为它表示您违反了Single Responsibility Principle(SRP)。 SRP指导您保持课堂规模小,重点突出,最重要的是:可维护。

  

还有其他选项不会让我的代码混乱吗?

绝对:制作较小的课程。当我们使用MVC控制器对特定概念的方法进行分组时,MVC控制器通常会变得非常庞大,例如客户'或者'订购'。然而,这意味着控制器是一个不断增长的类,必须针对任何新功能进行更改。这违反了Open/closed Principle,它告诉我们应该努力建立一个系统,我们可以在不触及现有类的情况下插入新功能。

因此,解决方案不是恢复到Service Locator anti-pattern或属性注入,而是创建更小的类来完成一个特定的事情。构造函数注入应该是应用依赖注入的主要方式,即使在类库中也是如此。

答案 1 :(得分:0)

您的控制器似乎正在将存储库转移到其他类。让Ninject代替你提供这些课程:

x86_64

您不必编写public class Controller { public Controller(IDependencyFactory dependency) { } } public interface IDependencyFactory { IDependency CreateDependency(); } public interface IDependency { } public class Dependency : IDependency { public Dependency() { } } public class Program { public static void Main() { var standardKernel = new StandardKernel(); standardKernel.Bind<IDependencyFactory>().ToFactory(); standardKernel.Bind<IDependency>().To<Dependency>(); } } 的实现,该实现由工厂扩展程序处理。你的IDependencyFactory - 类将获得Ninject注入的依赖项。

答案 2 :(得分:0)

好吧,我似乎已经找到了一种方法来做到这一点,看起来并不臭!

我曾经想过如果您使用MVC,那么您将通过构造函数获取存储库,这是解决依赖关系的唯一方法。

在完成将可重用代码的部分移动到IoC友好接口及其实现之后,我注意到当您在控制器构造函数中创建引用IMyInterface时,实现类的默认构造函数会运行,您可以拉出其他IoC类,如从那里解决了存储库。

这可能是常识,但它确实使事情更加整洁,并解决了我遇到的问题。

实施例

控制器

public IDefaultTemplateManager DefaultTemplateManager { get; set; }

public DefaultController(IDefaultTemplateManager defaultTemplateManager) {
    this.DefaultTemplateManager = defaultTemplateManager;
}

public ActionResult MyAction(FormCollection collection) {
    DefaultTemplateManager.Process("MyKeyHere");
    View();
}

IDefaultTemplateManager

public interface IDefaultTemplateManager {
    ProcessResponse Process(string UniqueKey, DefaultTemplateManagerEditMode DatabaseName, string DefaultTemplateName);
}

DefaultTemplateManager

    public class DefaultTemplateManager : IDefaultTemplateManager {

        protected IRepository<MyEntity1> MyEntityRepo1 { get; set; }
        protected IRepository<MyEntity2> MyEntityRepo2 { get; set; }
        protected IRepository<MyEntity3> MyEntityRepo3 { get; set; }
        protected IRepository<MyEntity4> MyEntityRepo4 { get; set; }
        protected IRepository<MyEntity5> MyEntityRepo5 { get; set; }
        protected IRepository<MyEntity6> MyEntityRepo6 { get; set; }

        public DefaultTemplateManager(IRepository<MyEntity1> MyEntityRepository1, IRepository<MyEntity2> MyEntityRepository2, IRepository<MyEntity3> MyEntityRepository3, IRepository<MyEntity4> MyEntityRepository4, IRepository<MyEntity5> MyEntityRepository5, IRepository<MyEntity6> MyEntityRepository6, ) {
            this.MyEntityRepo1 = MyEntityRepository1;
            this.MyEntityRepo2 = MyEntityRepository2;
            this.MyEntityRepo3 = MyEntityRepository3;
            this.MyEntityRepo4 = MyEntityRepository4;
            this.MyEntityRepo5 = MyEntityRepository5;
            this.MyEntityRepo6 = MyEntityRepository6;
        }

        public ProcessResponse Process(string UniqueKey) {
            /* Do Work */
        }