构建项目& C#中大型winforms应用程序的依赖关系

时间:2008-09-30 07:13:13

标签: visual-studio winforms architecture projects-and-solutions

更新
这是我最常访问的问题之一,但我仍然没有真正为我的项目找到满意的解决方案。我在回答另一个问题时读到的一个想法是创建一个工具,可以为您从列表中选择的项目“动态”构建解决方案。我还没试过。


如何构建一个非常大的应用程序?

  • 一个大解决方案中的多个小型项目/组件?
  • 一些大项目?
  • 每个项目一个解决方案?

在没有一个解决方案的情况下,如何管理依赖关系? 注意:我正在寻找基于经验的建议,而不是您在Google上找到的答案(我可以自己做)。

我目前正在开发一个应用程序,它有80个dll,每个都在自己的解决方案中。管理依赖项几乎是一项全职工作。有一个自定义的内部“源代码控制”,增加了复制依赖dll的功能。对我来说似乎是次优解决方案,但有更好的方法吗?我担心,在80个项目的解决方案上工作会非常粗糙。

(上下文:winforms,而不是web)

编辑:(如果您认为这是一个不同的问题,请给我发表评论)

在我看来,它们之间存在相互依存关系:

  • 应用程序的项目/解决方案结构
  • 文件夹/文件结构
  • 源代码管理的分支结构(如果使用分支)

但如果可能的话,我很难将它们分开来单独考虑。

我问过另一个相关问题here

9 个答案:

答案 0 :(得分:5)

来源控制

我们有20或30个项目被构建到4或5个分立解决方案中。我们正在使用Subversion for SCM。

1)我们在SVN中有一棵树,包含按命名空间和项目名称逻辑组织的所有项目。根目录下有一个.sln可以构建它们,但这不是必需的。

2)对于每个实际的解决方案,我们在SVN中使用SVN创建了一个新的中继文件夹:对所有必需项目的外部引用,以便从主树下的位置进行更新。

3)在每个解决方案中,都是.sln文件以及一些其他必需文件,以及该解决方案独有且不在解决方案之间共享的任何代码。

有许多较小的项目有时会有点痛苦(例如TortoiseSVN更新消息会使所有这些外部链接变得混乱)但确实具有不允许循环的依赖性的巨大优势,因此我们的UI项目依赖于在BO项目上但是BO项目不能引用UI(也不应该引用它们。)。

<强>建筑 我们已完全切换到使用MS SCSF and CAB enterprise模式来管理我们的各种项目在Win Forms界面中组合和交互的方式。我不确定你是否遇到同样的问题(多个模块需要在通用表单环境中共享空间),但如果你这样做,那么这可能会为你如何构建和组装解决方案带来一些理智和惯例。

我提到这是因为SCSF倾向于将BO和UI类型函数合并到同一个模块中,而之前我们维护了严格的3级策略:

FW - 框架代码。其功能与软件问题相关的代码。 BO - Business Objects。其功能与问题域关注相关的代码。 UI - 与UI相关的代码。

在那种情况下,依赖性严格来说是UI - &gt; BO - &gt; FW

我们发现即使在使用SCSF生成的模块时我们也可以保持这种结构,所以世界上一切都很好: - )

答案 1 :(得分:2)

要管理依赖项,无论您拥有多少程序集/命名空间/项目,都可以浏览工具NDepend

Personnaly,如果需要,我会在一个或几个解决方案中培养一些大型项目。我在这里写了关于这样做的动机:Benefit from the C# and VB.NET compilers perf

答案 2 :(得分:1)

我认为,拥有包含所有80个项目的解决方案非常重要,即使大多数开发人员大多数时间都使用其他解决方案。根据我的经验,我倾向于使用一个大型解决方案,但为了避免每次遇到F5时重建所有项目的痛苦,我去解决方案资源管理器,右键单击我现在不感兴趣的项目,并做“卸载项目”。这样,项目就停留在解决方案中,但它不会让我付出任何代价。

话虽如此,80是一个很大的数字。根据这些80分解为dicrete子系统的程度,我可能还会创建其他每个包含有意义子集的解决方案文件。这将节省我许多右键单击/卸载操作的工作量。然而,事实上你有一个很大的解决方案意味着它们总是能够确定它们之间的相互依赖关系。

在我使用过的所有源代码控制系统中,他们的VS集成选择将.sln文件放在源代码管理中,并且许多代码无法正常工作除非该.sln文件是在源代码管理中。我发现这很有趣,因为.sln文件过去被认为是个人的东西,而不是项目范围的东西。我认为唯一一种绝对值得源代码控制的.sln文件是包含所有项目的“一大解决方案”。例如,您可以将其用于自动构建。正如我所说,个人可能会为了方便而创建自己的解决方案,我并不反对那些进入源代码控制的人,但他们对个人而言比对项目更有意义。

答案 3 :(得分:1)

我认为最好的解决方案是将其分解为更小的解决方案。在我目前工作的公司,我们遇到了同样的问题;解决方案中的80个项目++。我们所做的,是分成几个较小的解决方案,项目属于一起。来自其他项目的相关dll构建并链接到项目中,并与项目一起签入源控制系统。它使用更多的磁盘空间,但磁盘很便宜。这样做,我们可以继续使用项目的第1版,直到升级到1.5版是绝对必要的。在决定升级到其他版本的dll时,你仍然可以添加dll。谷歌代码上有一个名为TreeFrog的项目,它展示了如何构建解决方案和开发树。它还没有包含文件,但我想你可以通过查看结构来了解如何做到这一点。

答案 4 :(得分:1)

我见过的方法运行良好的是有一个包含所有项目的大解决方案,允许测试项目范围的构建(没有人真正使用它来构建,虽然它太大了。),然后让开发人员使用较小的项目,将各种相关项目组合在一起。

这些确实依赖于其他项目,但除非接口发生变化,或者需要更新他们使用的dll版本,否则他们可以继续使用较小的项目而不必担心其他任何问题。 因此,当他们正在处理它们时,他们可以签入项目,然后在其他用户开始使用它们时将其固定(在更改版本号后)。

最后一周一次或两次甚至更频繁地使用固定代码重建整个解决方案,从而检查集成是否正常工作,并为测试人员提供良好的构建以进行测试。

我们经常发现代码的大部分内容并没有经常更改,所以它总是毫无意义地加载它。 (当你在处理较小的项目时。)

使用这种方法的另一个好处是,在某些情况下,我们有一些功能需要几个月才能完成,通过使用上述方法意味着可以继续而不会中断其他工作流。

我认为一个关键标准是你的解决方案没有很多交叉依赖关系,如果这样做,这种方法可能不合适,但如果依赖关系更加有限,那么这可能就是这样。

答案 5 :(得分:1)

对于我参与过的几个系统,我们为不同的组件提供了不同的解决方案。每个解决方案都有一个公共输出文件夹(带有Debug和Release子文件夹)

我们在解决方案中使用了项目引用,并在它们之间引用了文件。每个项目都使用“参考路径”来定位其他解决方案中的装配。我们必须手动编辑.csproj.user文件,以便将$(Configuration)msbuild变量添加到引用路径,因为VS坚持验证路径。

对于VS之外的构建,我编写了msbuild脚本,以递归方式识别项目依赖项,从subversion中获取它们并构建它们。

答案 6 :(得分:1)

由于以下原因,我放弃了项目参考(尽管你的宏听起来很棒):

  • 在有时依赖项目存在且有时没有依赖项目的不同解决方案之间切换并不容易。
  • 需要能够自己打开项目并构建它,并独立于其他项目部署它。如果使用项目引用构建,这有时会导致部署问题,因为项目引用导致它查找特定版本或更高版本,或类似的东西。它限制了交换和输出不同版本的依赖项的混合和匹配能力。
  • 此外,我的项目指向不同的.NET Framework版本,因此无论如何都不会总是发生真正的项目引用。

(仅供参考,我所做的一切都是针对VB.NET的,所以不确定C#的行为是否存在细微差别)

所以,我:

  • 我针对任何在解决方案中打开的项目构建,而不是来自全局文件夹的项目,例如C:\ GlobalAssemblies
  • 我的持续集成服务器在网络共享上保持最新状态,我有一个批处理文件可以将任何新内容同步到我的本地文件夹。
  • 我有另一个本地文件夹,例如C:\ GlobalAssembliesDebug,其中每个项目都有一个post build步骤,只有在DEBUG模式下才能将bin文件夹的内容复制到此debug文件夹。
  • 每个项目都将这两个全局文件夹添加到其参考路径中。 (首先是C:\ GlobalAssembliesDebug,然后是C:\ GlobalAssemblies)。我必须手动将此引用路径添加到.vbproj文件中,因为Visual Studio的UI会将它们添加到.vbprojuser文件中。
  • 我有一个预构建步骤,如果处于RELEASE模式,则删除C:\ GlobalAssembliesDebug中的内容。
  • 在作为主机项目的任何项目中,如果我需要复制非dll(文本文件输出到我需要的其他项目的bin文件夹),那么我在该项目上放置一个prebuild步骤将它们复制到主持项目。
  • 我必须在解决方案属性中手动指定项目依赖项,以使它们以正确的顺序构建。

所以,这样做是:

  • 允许我在任何解决方案中使用项目,而不会搞乱项目引用。
  • Visual Studio仍允许我进入解决方案中打开的依赖项目。
  • 在DEBUG模式下,它针对打开的加载项目构建。所以,首先它看向C:\ GlobalAssembliesDebug,如果不存在,则查看C:\ GlobalAssemblies
  • 在RELEASE模式下,由于它删除了C:\ GlobalAssembliesDebug中的所有内容,因此它只查看C:\ GlobalAssemblies。我想要这样做的原因是,发布的版本不会针对我的解决方案中暂时更改的任何内容构建。
  • 轻松地轻松加载和卸载项目。

当然,这并不完美。调试体验不如项目引用那么好。 (不能做“去定义”并让它正常工作)和其他一些古怪的东西。

无论如何,这就是我努力为我们做最好的事情。

答案 7 :(得分:0)

我们在主分支上的源控件上有一个巨大的解决方案。

但是,每个从事项目较小部分工作的开发人员/团队都有自己的分支,其中包含一个只需要很少项目的解决方案。通过这种方式,该解决方案足够小,易于维护,并且不会影响更大解决方案中的其他项目/ dll。

但是,有一个条件:解决方案中不应该有太多互连的项目。

答案 8 :(得分:0)

好的,已经消化了这些信息,并且还回答了关于项目引用的this question,我目前正在使用这种配置,这似乎“对我有用”:

  • 一个很大的解决方案,包含应用程序项目和所有依赖项组装项目
  • 我保留了所有项目引用,并对一些动态实例化的程序集进行了一些额外的手动依赖项调整(右键单击项目)。
  • 我有三个解决方案文件夹(_Working,Synchronized和Xternal) - 假设我的源代码控制没有与VS( sob )集成,这使我可以快速拖放项目_Working和Synchronized所以我不会忘记变化。 XTernal文件夹用于“属于同事”的程序集。
  • 我自己创建了一个'WorkingSetOnly'配置(Debug / Release下拉列表中的最后一个选项),它允许我限制在F5 / F6上重建的项目。
  • 就磁盘而言,我将所有项目文件夹只放在几个文件夹中的一个(所以只有一个级别的项目分类)
  • 所有项目构建(dll,pdb&amp; xml)到同一个输出文件夹,并且与参考路径具有相同的文件夹。 (并且所有引用都设置为“不要复制”) - 这使我可以选择从我的解决方案中删除项目并轻松切换到文件引用(我有一个宏)。
  • 与我的'Projects'文件夹处于同一级别,我有一个'Solutions'文件夹,我在其中为某些程序集维护单独的解决方案 - 以及特定于程序集的测试代码(例如)和文档/设计等。

目前这种配置对我来说似乎没有问题,但是最重要的考验是尝试将它卖给我的同事,看看它是否会像团队设置一样飞行。

目前尚未解决的弊端:

  • 我仍然遇到个别装配解决方案的问题,因为我并不总是希望包含所有相关项目。这会与“主”解决方案产生冲突。我已经解决了这个问题(再次)一个宏,它将破坏的项目引用转换为文件引用,并在项目被添加回来时恢复对项目引用的文件引用。
  • 遗憾的是,我没有办法(我发现到目前为止)将构建配置链接到解决方案文件夹 - 能够说'在此文件夹中构建所有内容'是有用的 - 就目前而言,我必须更新此内容用手(痛苦,容易忘记)。 (您可以右键单击解决方案文件夹进行构建,但这不能处理F5方案)
  • 解决方案文件夹实现中存在(次要)错误,这意味着当您重新打开解决方案时,项目将按添加顺序显示,而不是按字母顺序显示。 (我打开了一个bug with MS,显然已经纠正了,但我想VS2010)
  • 我不得不卸载CodeRushXPress加载项,因为它阻塞了所有代码,但这是在修改构建配置之前,所以我将再试一次。

摘要 - 在提出这个被证明有用的问题之前我不知道的事情:

  1. 使用solution folders组织解决方案而不会弄乱磁盘
  2. 创建构建配置以排除某些项目
  3. 能够手动定义项目之间的依赖关系,即使它们使用文件引用
  4. 这是我最热门的问题,所以我希望这个答案可以帮助读者。我对其他用户的进一步反馈仍然很感兴趣。