管理反映依赖关系的依赖关系

时间:2013-08-20 21:29:03

标签: visual-studio reflection dependencies mef dependency-management

我目前正在使用包含大约100个项目的大型解决方案。至少有10个项目是可执行应用程序。一些库项目通过MEF和反射而不是直接引用作为插件导入。如果所需的插件自己的依赖项没有被复制到使用它的可执行项目的输出或插件目录中,我们将在运行时获得反射错误。

我们已经尝试或讨论了以下解决方案,但它们似乎都不合适:

  1. “硬”参考:最初,我们让可执行项目引用了他们需要的其他项目,即使它们最终将作为可选插件导入。这很快就失去了团队成员的青睐,他们需要制作排除某些插件的构建,并且喜欢卸载这些项目。这也使得很难使用Resharper或其他工具来清理未使用的引用并删除过时的第三方库,而不会意外地删除对所需插件自身依赖项的“未使用”引用。
  2. 构建后复制(预构建“拉”):在短时间内,高级团队成员将所有插件项目设置为xcopy,其输出输出自身为已知的“ DependencyInjection“文件夹作为后期构建事件。需要这些插件的项目将具有预构建事件,将每个所需的插件xcopying到它们自己的输出目录。虽然这意味着插件项目“正确”不知道它们可能被使用的地方,但这引起了两个主要问题。首先,任何时候在插件项目中进行更改时,他们必须单独构建(按顺序)插件项目,然后是他们将测试它的可执行项目(以获取要复制的文件)。重建所有会更方便,但太慢。其次,持续集成构建必须已经重新配置,因为它将所有内容编译在一个目录中,并且只有在所有内容都成功构建时才会关注。
  3. 构建后复制(推送):本解决方案以xcopy开始,现在主要在插件项目的后期构建事件中使用robocopy将所需文件直接复制到可执行文件的插件文件夹中使用它们的项目。这非常有效,因为如果在插件中进行更改,可以直接使用调试器运行。此外,CI构建不会中断,并且用户为各种构建禁用某些“可选”插件项目不会从缺少的引用中获得构建错误。这似乎仍然是hackish,并且在所有单独的后构建窗口中维护是很麻烦的,这些窗口相当小并且无法扩展。当可执行项目从项目重组中移出或重命名时,我们在听到隔夜自动化测试结果后的第二天才发现损坏的引用。
  4. 带有参考文献的“虚拟”项目:简要介绍了一个想法,包括为每个不同的可执行构建配置创建空项目,并返回到那些的硬引用方法。每个人都会使用自己的引用来收集插件及其依赖项。他们还会引用实际的可执行文件并将其复制。然后,如果想要在特定配置中运行特定的可执行文件,那么您将运行其虚拟项目。这个似乎特别臃肿,从未尝试过。
  5. NuGet :在我对NuGet的熟悉程度上,这似乎非常适合使用包,除非我不知道如何在一个解决方案中实现内部。我们谈到了破解解决方案,但团队的许多成员都强烈反对。是否可以使用NuGet包含来自同一解决方案的包?
  6. 对于这种情况,最佳做法是什么?有没有比上述任何一个更好的解决方案来管理这样的反映依赖关系的依赖关系,还是上述最佳选择之一的改进?

3 个答案:

答案 0 :(得分:1)

好的,所以我在这个答案中假设每个开发人员需要在本地持续拥有所有100个程序集(调试模式)来完成它的工作(开发,编译,冒烟测试,运行自动测试)。

你提到RebuildAll需要很长时间。通常,这种症状是由太多的程序集+构建过程未合理化引起的。因此,首先要尝试将100个程序集合并到尽可能少的程序集中,并避免使用Copy Local = true之类的东西。效果将更快(如10x)RebuildAll进程。请记住,程序集是物理假象,它们仅适用于物理内容(如插件,按需加载,测试/应用程序分离......)。我写了一本白皮书详细介绍了我对这个主题的看法:http://www.ndepend.com/WhiteBooks.aspx

Partitioning code base through .NET assemblies and Visual Studio projects (8 pages)

  • 创建程序集的常见有效和无效原因
  • 提高Visual Studio解决方案编译性能(最高可达x10)
  • 组织开发环境

在白皮书的建议中,其中一个想法是避免引用项目,而是引用程序集。这样你就有责任填写 Project>右键单击>项目依赖项将定义项目>右键单击>项目构建顺序。如果您决定继续处理100个程序集,那么定义此设置代表了一种努力,但作为奖励,高级(可执行)项目可以依赖于仅由反射使用的库,这将解决您的问题。

你衡量Lines of Code in terms of # of PDB sequences points了吗?我估计,直到200K到300K的限制做RebuildAll(在白皮书中描述的优化)应该需要5到10秒(在一台体面的笔记本电脑上),它仍然可以接受。如果你的代码库非常大并且超出了这个限制,那么你需要打破我的第一个假设并找到一种开发人员不需要所有程序集来完成其工作的方法(在这种情况下我们可以进一步讨论这个)

免责声明:此答案引用我创建的工具NDepend网站上的资源,现在管理其开发。

答案 1 :(得分:1)

我一直处在像你这样的境地。我们有近100个项目。我们也在使用MEFSystem.AddIn。一开始我们有一些解决方案。我正在研究包括核心组件及其测试的核心解决方案。每个插件类别在单独的解决方案中,包括合同,实现(一些插件具有多个实现)和测试,以及一些测试主机以及核心组件。稍后我们添加了一个包含所有项目的解决方案,在尝试了一些您提到的方法后,我们决定执行以下操作:

  1. 保留必填参考
  2. 所有可执行项目都设置为输出到公共位置(一个用于调试,一个用于发布配置),
  3. 所有不应引用的项目都设置为输出到这些公共位置
  4. 其他人引用的所有项目保持不变,每个参考都设置为Copy Local = true
  5. 测试保持不变。
  6. 虽然建设一切都很慢,但我们没有任何其他问题。当然,有近100个项目表明设计可能过于模块化,而且 Patrick 建议,我们应该尝试压缩它。

    无论如何,您可以在几个小时内尝试这种方法,也许不是设置Copy Local = true,而是尝试设置4中提到的所有项目的输出文件夹,将其输出设置为公共位置。我们不知道此设置会降低构建过程的速度,因为 Patrick 会提及。

    PS。我们从未尝试使用NuGet,因为我们没有足够的资源和时间来试验它。虽然看起来很有希望。

答案 2 :(得分:0)

我们正在启动一个新项目,我正在寻找这个类似问题的“最佳实践”解决方案。对我们来说,我们可以将项目分为两类:1)平台组件,它们提供全面的通用服务集合; 2)垂直方案,它们将执行业务特定功能。

过去我们使用了一个带有简单UI的Visual Studio插件,允许开发人员指定一个通用程序集路径来复制输出程序集,然后引用所有程序集(无论它们位于不同的解决方案中)装配文件夹。

我正在寻找NUGET,但你必须做的创建和维护NUGET包的绝对工作是惩罚性的。

这是一种非常常见的情况,并且非常有兴趣了解其他人如何解决它。