【问题标题】:What is the Best Way to Organize a ASP.Net MVC Solution Using Dependency Injection?使用依赖注入组织 ASP.Net MVC 解决方案的最佳方法是什么?
【发布时间】:2009-06-08 01:25:01
【问题描述】:

我正在开发一个新的 ASP.Net MVC 项目,我正在使用这个项目进入 DI。我很确定我将使用结构图,但这不是我要问的。我想弄清楚的是如何最好地组织我的解决方案。单元测试项目和模型是否都获得了一个配置文件来映射它们的依赖关系,或者是否有一个类来统治它们?

另外,在我深入这个之前,有没有什么新手陷阱需要避免?

非常感谢,大家.....

更新 我应该补充一点,当我说“组织解决方案”时,我指的不是文件/文件夹等的数量,而是如何构造与 DI 相关的类。特别是如何管理引导程序。我可以看出我的措辞不当可能会导致混乱。

【问题讨论】:

  • 我的 StructureMap 新手陷阱是 Medium Trust 下的安全权限异常。如果您的应用将在中等信任环境中运行,您将需要查看备用 DI 容器。

标签: asp.net-mvc dependency-injection inversion-of-control structuremap


【解决方案1】:

如果您是该项目的唯一工作人员,我会首先做对您有意义的事情。没有什么比强加给您不直观的目录或项目结构更糟糕的了。 BaseController 类是在 \Core\ 文件夹还是 \Controller\ 文件夹中?我个人会查看控制器,但有些人发誓它应该在 \Core\ 或 \Bases 中。

第一个新手陷阱是认为您可以以错误的方式组织代码,这在某种程度上反映了项目的成功。我见过一个文件夹中有 30 个文件的项目,而其他项目中有 30 个文件的 20 个文件夹。

第二个新手陷阱忘记了,与其他语言相比,您可以从 Visual Studio 的出色智能感知、代码导航工具和重构支持中获益。您还有一个编译器,它可以让放错文件的痛苦大大减少。如果你把东西放在“错误”的地方,没关系,你总能找到它并将它拖到需要的地方。

老实说,我现在正在做一个项目,我什至不确定某些类在我的文件结构中的位置。 Go To Definition/Declaration 是我经常使用的键盘快捷键。因为只有我在使用代码,所以这很好。如果我必须在项目中添加另一个开发人员,我可能会清理干净。

我个人倾向于将接口及其实现类型放在同一个文件夹中。 IPaymentGateway 与 AuthorizeNetGateway 和 PaypalGateway 位于同一文件夹中。如果我无法在我的解决方案资源管理器侧边栏中一次查看该文件夹中的所有文件,那么我将所有网关文件移动到 \Gateway\ 文件夹中。

在添加依赖注入的情况下,我建议您只关注命名空间爆炸。您可以做的最糟糕的事情是使用长 using 声明和别名将引导程序和文件弄得一团糟。

ForRequestedType<Customer>

比干净

using KevDog.Models
using Customer=KevDog.Models.Customer

ForRequestedType<KevDog.Models.Customer>

避免此问题的另一种方法是在命名时明确说明:Customer、CustomerViewModel、CustomerController、CustomerDataRow、CustomerView

对于 TDD,您几乎必须有两个引导程序来管理您的具体类型。你真的不希望你的单元测试使用 AuthorizeNetGateway : IPaymentGateway,而是 StubGateway : IPaymentGateway。

现在我也是 DI 的新手,所以我倾向于让事情变得非常简单,并反映 101 级教程和文档。仅当特定情况需要并且您确切知道为什么这样做时,才应使用基于构建配置的动态注入。

我通常也会保留 MVC 应用程序的默认结构。让您的代码与 99% 的教程和视频具有相同的结构更容易。

希望这会有所帮助。

【讨论】:

  • 谢谢jfar!关于 TDD 的评论确实是我要问的那种东西。我认为每个项目的引导程序的想法是要走的路。一个在单元测试项目中,一个在MVC项目中
【解决方案2】:

鼓励更好的 TDD。有两个测试项目和/或命名空间 X.Unit.Tests & X.Integrations.Tests。

我的 DI 代码在我的主项目中的“命名空间目录”(/Config) 中,但在我的集成代码测试中,如果我的基本装置或设置中需要,我可能只调用这些注册表或覆盖。

例如

/Config/ServiceRegistry.cs /Config/RepositoryRegistry.cs /Config/Bootstrapper.cs

在 global.asax 中我调用 Bootstrapper.Init() 这将调用 x.AddRegistry(new ServiceRegistry()) 等等。

在我的单元测试中,您不需要只在集成测试中使用 DI。在我的集成测试中,例如如果我正在通过数据库测试 NHibernate,我可能会在 TestSetUp 中使用 RepositoryRegistry 初始化 SM,并使用仅包装 GetInstance() 的辅助方法。

我不会拆分到 .Bootstraper 和 .Domain 项目,除非我必须... 三个项目,X、X.UnitTests、X.Integration,如果您以后需要更多移动。我来自一个背景/公司强制执行的数十个项目,第一次减少感觉很脏,但现在不是,我会快速运行并在以后根据需要重新组织解决方案结构。

【讨论】:

    【解决方案3】:

    这是我第一次尝试为自己解决同样的问题,但由于这是我的第一次尝试,我希望人们可以尽可能多地评论或批评它,就像我希望它可能成为你的一个可能的解决方案一样:

    public VatManager()
     : this(new VatManagerRegistry()) { }
    
    public VatManager(Registry registry)
     : this(new Action<IInitializationExpression>(x => { x.AddRegistry(registry); }))
      {
      }
    
    public VatManager(Action<IInitializationExpression> action)
      {
       ObjectFactory.Initialize(action);
       data = ObjectFactory.GetInstance<IVatManagerData>();
      }
    

    我有三个构造函数重载 - 无参数默认构造函数了解需要创建以在生产环境中使用的具体 StructureMap 注册表。另外两个允许实例化此管理器类的其他代码提供自己的 StructureMap 注册表或操作,以便它们可以自己控制依赖注入,例如在提供模拟而不是具体实例的自动化测试的情况下依赖关系。 我应该补充一点,此解决方案并非特定于 ASP.NET MVC 上下文,并且不会从 *.config 文件中提取任何配置信息。

    【讨论】:

      猜你喜欢
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-03
      • 1970-01-01
      • 1970-01-01
      • 2020-03-31
      相关资源
      最近更新 更多