无痛的本地开发,同时也引用NuGet包

时间:2014-12-30 19:30:25

标签: c# visual-studio visual-studio-2013 nuget nuget-package

我正在尝试发布和使用版本化的类库的NuGet包,同时避免了本地开发的麻烦。以下是Visual Studio解决方案布局示例:

| Libraries
  | LibraryA
  | LibraryB
  | LibraryC
| Applications
  | ApplicationD
  | ApplicationE

这是一个包含共享类库和多个应用程序的单一解决方案。目前,应用程序对类库的引用是本地解决方案引用。

我想要做的是将库(A,B,C)发布为版本化的NuGet包,然后由应用程序根据需要引用它们(D,E)。这允许对共享库的更改独立于对已部署的应用程序的更新。如果没有这个,更改一个库可能会导致二进制文件在十几个或更多应用程序中发生变化,所有这些都在技术上需要进行测试。这是不可取的,使用NuGet进行版本控制可以解决这个问题。

但是,我们要说我想同时更新LibraryA和ApplicationD的内容。为了在切换到NuGet之后执行此操作,我将不得不对LibraryA进行更改,提交它们,等待创建包,告诉ApplicationD更新其对LibraryA的引用,然后在ApplicationD中进行测试或开发。这比使用本地解决方案引用同时处理两者要复杂得多。

什么是更好的方法来获得我的共享类库的版本化NuGet包的健壮性,同时保持开发简单,即使它跨越多个项目和应用程序?我发现的唯一其他解决方案都涉及太多开销或头痛,例如不得不在NuGet包和本地项目之间不断更改ApplicationD的引用。

编辑:为澄清前提,此问题假设如下:

  • 架构(解决方案和项目组织)无法重新组织
  • 共享库将以非平凡的频率发生变化
  • 更改共享库不能强制更新任何应用程序
  • 应用程序可以引用不同版本的共享库

7 个答案:

答案 0 :(得分:19)

虽然需要一些工作,但可以手动编辑.csproj文件,以便通过向适当的引用添加Condition属性来设置条件引用。

编辑我已将这些条件移到ItemGroups中,因为这似乎是我提到的生产代码的工作方式,并且在VS 2013中提到这是一个可能的问题。

<ItemGroup Condition="'$(Configuration)' == 'Debug Local'">
    <!-- Library A reference as generated by VS for an in-solution reference, children unmodified -->
    <ProjectReference>...
</ItemGroup>

<ItemGroup Condition="'$(Configuration)' == 'Debug NuGet'">
    <!-- Library A reference as generated by NuGet, child nodes unmodified --> 
    <Reference Include="LibraryA">...
</ItemGroup>

这将允许您在项目D&amp; E,“Debug NuGet”与“Debug Local”的配置,它们以不同的方式引用库。如果您有多个解决方案文件,其配置映射到项目中的相应配置,最终用户将永远不会看到超过“调试”和“发布”的大多数操作,因为这些是解决方案配置,并且只会需要打开完整的解决方案来编辑​​A,B和&amp; C项目。

现在,至于获得A,B和&amp; C项目不受影响,您可以将它们设置在标记为subrepo的文件夹下(假设您正在使用支持此功能的SCM,例如Git)。大多数用户永远不需要提取subrepo因为他们没有访问ABC项目,而是从NuGet获取。

维护方面,我可以保证VS不会编辑条件引用,并且在编译期间会尊重它们 - 我已经完成了VS 2010和2013(编辑:专业版,尽管我有在工作中使用相同的条件参考项目深入研究。请记住,与VS相比,引用可以与版本无关,使NuGet成为需要维护版本的唯一地方,并且可以像任何其他NuGet包一样完成。虽然我很有希望,但我没有测试NuGet是否会与条件参考作斗争。

编辑谨慎地注意,条件引用可能会导致有关丢失DLL的警告,但实际上并不妨碍编译或运行。

答案 1 :(得分:9)

我知道这是一个2岁的帖子,但是在遇到同样的情况时才发现它。也为VS2015找到了这个,我正在测试它。我会回来调整我的答案。

https://marketplace.visualstudio.com/items?itemName=RicoSuter.NuGetReferenceSwitcherforVisualStudio2015

答案 2 :(得分:3)

我也面临类似的问题。一种有效的方法是使用本地存储库(基本上只是本地存储库中的一个文件夹),然后在库中添加构建后脚本。例如:假设您需要更新LibraryA的实现,然后在LibraryA的构建后事件中包括以下3个步骤:

  1. 检查本地存储库是否具有该版本的软件包;如果是,则将其删除

    rd /s /q %userprofile%\.nuget\packages\LibraryA\@(VersionNumber) -Recurse -ErrorAction Ignore

  2. 创建一个nuget包

    nuget pack LibraryA.csproj

  3. 将其推送到本地存储库

    nuget push LibraryA@(VersionNumber) -Source %userprofile%\.nuget\packages

这些步骤将确保在每次构建后始终针对该版本更新该软件包(我们必须这样做,因为nuget软件包是不可变的)

现在在ApplicationD中,您可以指向本地存储库(%userprofile%.nuget \ packages)以获取LibraryA;这样,在每次构建LibraryA之后,您都会在ApplicationD中收到它的更新版本

PS:要获取您的库的版本号,可以使用以下命令:Determine assembly version during a post-build event

答案 3 :(得分:2)

不幸的是,真的没有办法让两全其美。在我公司的内部,我们通过快速构建/部署过程有所缓解,通过引用NuGet包来抵消大部分负担。基本上,我们所有的应用程序都使用托管在本地NuGet存储库中的同一个库的不同版本。由于我们使用自己的软件来构建,部署和托管软件包,因此可以非常快速地更新库,然后在另一个解决方案中更新其NuGet软件包。基本上,我们发现的最快的工作流程是:

  1. 对库进行更改
  2. 自动构建和部署库的版本,增加1到内部NuGet提要
  3. 更新消费者应用程序中的NuGet包
  4. 从签到到更新消费项目的整个过程大约需要3分钟。 NuGet存储库还有一个符号/源服务器,可以极大地帮助调试。

答案 4 :(得分:1)

.NET Core(2.x ++)的更新

.NET Core 2.x实际上内置了此功能!

如果您在项目B中有一个对项目A的项目引用,并且项目A是具有适当程序包信息(Properties -> Package且您的NuGet程序包ID设置为Package id的.NET Standard或Core项目) ,那么您可以在项目B的.csproj文件中有一个常规项目参考:

<ItemGroup>
  <ProjectReference Include="..\..\A\ProjectA.csproj" />
</ItemGroup>

当您打包(dotnet pack)项目B时,由于项目A中的Package id,所生成的.nuspec文件将与该Package ID的NuGet依赖项一起设置与您可能拥有的其他NuGet引用,而不仅仅是包含内置的DLL文件。

<dependencies>
  <group targetFramework=".NETStandard2.0">
    <dependency id="Project.A" version="1.2.3" exclude="Build,Analyzers" />
    <dependency id="Newtonsoft.Json" version="12.0.2" exclude="Build,Analyzers" />
  </group>
</dependencies>

答案 5 :(得分:0)

在ApplicationD的属性中,转到“ 参考路径”选项卡,然后添加LibraryA的输出文件夹的路径。然后,如果更改并构建LibraryA,则下一版本的ApplicationD将使用修改后的LibraryA。

完成后,请不要忘记删除“参考路径”并更新参考的NuGet软件包版本。

答案 6 :(得分:0)

到目前为止,我不太干净但最快的解决方案是:

假定以下两个单独的解决方案:

VS解决方案1:包含以nuget包形式发布的库:

Solution1
|_ my.first.library
|_ my.second.library

VS解决方案2:包含应用程序,它们将上述一个或多个库用作PackageReference

Solution2
|_ my.first.application
|  |_ depends on nuget my.first.library (let's say v1.0.1)
|
|_ my.second.application

以防万一,我正在对my.first.library进行更改

我进行如下操作:

  1. 将代码更改为my.first.library并重新构建
  2. 导航到my.first.library的构建输出目录(例如<Solution1 directory>/my.first.library/bin/debug/netstandard2.0)并复制.dll.pdb文件
  3. 导航到当前正在使用的nuget feed的my.first.library的本地目录(例如,在C:\Users\user.name\.nuget\packages\my.first.library\1.0.1lib\netstandard2.0处),并将.dll.pdb文件替换为步骤1中生成的内容(可能进行备份)。
  4. 更改反映在my.first.application中。继续工作,并在需要时重复步骤1-4

优势:

  • 完全本地化。不需要次要的nuget提要。
  • .csproj / .sln文件进行零更改