如何使用依赖注入最佳地组织 ASP.Net MVC 解决方案?

14

我正在进行一个新的ASP.Net MVC项目的开发,并且正在使用这个项目来了解依赖注入。我相当确定我会选择Structure Map,但这不是我的问题所在。我想要弄清楚的是如何最好地组织我的解决方案。单元测试项目和模型都需要一个配置文件来映射它们的依赖关系吗?还是有一个类可以统治所有依赖项?

此外,在我进展过程中有没有需要避免的新手陷阱?

非常感谢大家.....

更新 我应该补充说明的是,当我说“组织解决方案”时,我并不是指文件夹/文件数量等问题,而是指如何构建与DI有关的类。特别是如何管理引导程序。我可以看出我的措辞可能会引起困惑。


1
我的StructureMap新手陷阱是在中等信任级别下出现了安全权限异常。如果您的应用程序将在中等信任环境中运行,您将需要寻找另一个DI容器。 - Ben Robbins
3个回答

11
如果你是唯一开发项目的人,我会先按照自己的想法来做。在你认为不直观的情况下强制采用某种目录或项目结构是最糟糕的事情。BaseController类是在\Core\文件夹还是\Controller\文件夹中?个人认为应该在Controller文件夹中,但有些人坚信它应该在\Core\或\Bases中。
第一个新手陷阱是认为你可以以错误的方式组织代码,而这些方式会反映在项目的成功上。我见过一个文件夹里有30个文件的项目,也见过其他项目有20个文件夹和30个文件。
第二个新手陷阱是忘记与其他语言相比,你拥有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项目中。 - KevDog

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,只需在集成测试中使用即可。例如,在我的IntegrationTests中,如果我通过NHibernate测试到数据库,我可能会在TestSetUp中使用RepositoryRegistry初始化SM,并使用一个包装GetInstance()的辅助方法。
直到绝对必须才会将其拆分为.Bootstraper和.Domain三个项目:X、X.UnitTests、X.Integration,如果需要更多,则稍后移动。我曾经来自一家强制执行数十个项目的公司,一开始感觉很肮脏,但现在不是了,我快速增长并根据需要重新组织解决方案结构。

0

这是我第一次尝试为自己解决同样的问题,但由于这是我的第一次尝试,我希望人们可以对其进行评论或批评,同时也希望它能作为您可能的一个解决方案:

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 Registry。其他两个允许实例化此管理器类的其他代码提供自己的StructureMap Registry或操作,以便他们可以控制依赖注入本身,例如在自动化测试中提供模拟而不是这些依赖项的具体实例。 我应该补充说明,这个解决方案并不特定于ASP.NET MVC上下文,并且不从*.config文件中提取任何配置信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接