如何让.NET Core项目复制NuGet引用来构建输出?

ron*_*975 78 c# msbuild csproj nuget .net-core

我正在尝试使用.NET Core编写一个插件系统,我的一个要求是能够将插件DLL及其依赖项分发给用户进行安装.但是,我无法弄清楚如何将我的NuGet依赖项包含为构建工件并将它们输出到构建文件夹,而不必将其dotnet publish用作hack.有什么方法可以在csproj中指定它吗?

Mar*_*ich 137

您可以将其添加到<PropertyGroup>csproj文件内部,以强制将NuGet程序集复制到构建的输出:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Run Code Online (Sandbox Code Playgroud)

但是,请注意,构建输出(bin/Release/netcoreapp*/*)不应该是可移植的和可分发的,输出dotnet publish是.但在您的情况下,将程序集复制到构建输出可能非常有用于测试目的.但请注意,您还可以使用DependencyContextapi来解析作为应用程序依赖关系图的一部分的DLL及其位置,而不是枚举本地目录.

  • @MartinUllrich 你能详细说明一下`DependencyContext`吗?如何使用它来查找不在应用程序目录中的 DLL?它到底在哪里? (4认同)
  • 它导致复制所有dll,而不仅仅是Nuget dll (3认同)
  • Core 2 我也得到了所有的 Microsoft DLL。不知道为什么,但在我只获得 NuGet 之前,它停止了这样做?恼人的 (3认同)
  • _“但是,请注意,构建输出(bin / Release / netcoreapp * / *)不应该是可移植和可分发的,dotnet发布的输出是”_那么当我去调试某些东西并且它应该如何工作时出现文件未找到异常,因为 nuget 包引用未复制到输出。这部分不可能是真的 (3认同)
  • 对我不起作用asp.net核心不复制System.ValueTuple.dll (2认同)

小智 10

我正在使用 .NET 5,这是我对类似问题的解决方案。

结构: Project-A(包含Selenium Nuget References,以及selenium代码) Project-B(单元测试项目,调用Project-A中的方法)

问题: 构建解决方案时,chromedriver.exe 文件出现在 Project-A bin 文件夹中,但不会复制到 Project-B bin 文件夹中,因此单元测试无法执行。抛出异常,提示未找到 chromedriver.exe。

解决方案: 修改 Selenium ChromeDriver NuGet 包引用的 Project-A 中的属性,仅将“contentfiles;analyzers”视为私有资产。如果未指定,则默认值为“contentfiles;analyzers;build”。现在,这意味着可以将构建的输出文件流向父引用项目,但不能流向内容文件或分析器,因为“构建”以前也被视为私有资产,不会流向父项目。

之前(在 Project-A.csproj 中):

<ItemGroup>
  <PackageReference Include="Selenium.Support" Version="3.141.0" />
  <PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
  <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="87.0.4280.8800" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

之后(在 Project-A.csproj 中):

<ItemGroup>
  <PackageReference Include="Selenium.Support" Version="3.141.0" />
  <PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
  <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="87.0.4280.8800">
    <PrivateAssets>contentfiles;analyzers</PrivateAssets>
  </PackageReference>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

我在此链接中找到了此信息: https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets

希望这对某人有帮助!祝你好运。


Xee*_*vis 8

您可以使用PostBuildEvent在构建时自动执行模块部署.

要在构建文件夹中获取NuGet程序集,请在模块的csproj中添加

<PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

使用包含/排除(根据需要修改路径)定义所需的模块文件

<ItemGroup>
    <ModuleFiles
      Include="$(TargetDir)*.dll"
      Exclude="$(TargetDir)System*.dll;$(TargetDir)Microsoft*.dll"
      DestinationPath="$(SolutionDir)src\MyProject\Modules\MyModule\%(Filename)%(Extension)">
    </ModuleFiles>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

将您的构建文件夹重置为默认值并添加PostbuildEvent

<Target Name="PublishModule" AfterTargets="PostBuildEvent" Inputs="@(ModuleFiles)" Outputs="@(ModuleFiles->'%(DestinationPath)')">
    <WriteLinesToFile File="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
    <Copy SourceFiles="@(ModuleFiles)" DestinationFiles="@(ModuleFiles->'%(DestinationPath)')" />
    <Delete Files="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
</Target>
Run Code Online (Sandbox Code Playgroud)

我包括app_offline来回收应用程序,如果它已经运行,以避免文件使用错误.


Mik*_*ner 8

添加

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Run Code Online (Sandbox Code Playgroud)

没有用,但将其添加到 Framework .csproj 文件中:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
Run Code Online (Sandbox Code Playgroud)

做过。


T.S*_*.S. 5

我以更简单的方式“解决”(创建了解决方案)这个问题。

在构建后

dotnet publish "$(ProjectFileName)" --no-build -o pub
xcopy "$(ProjectDir)pub\3rdPartyProvider.*.dll" "$(OutDir)"
Run Code Online (Sandbox Code Playgroud)

pub是您希望将已发布内容暂存的文件夹

注意:根据dotnet.exe您使用的版本,命令--no-build可能不可用。

例如,v2.0.3中不可用;并在 v2.1.402 中提供。我知道VS2017 Update4有v2.0.3。Update8 有 2.1.x

更新:

上面的设置将在基本调试环境中工作,但将其放入构建服务器/生产环境中还需要更多。在我必须解决的这个特定示例中,我们分别构建Release|x64Release|x86。所以我把两者都考虑在内。但为了支持构建后dotnet publish命令,我首先添加RuntimeIdentifier到项目文件中。

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  <OutputPath>..\..\lib\</OutputPath>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
  <OutputPath>..\..\lib\</OutputPath>
  <RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>
Run Code Online (Sandbox Code Playgroud)

为什么我需要它,为什么你不需要它就可以逃脱?我需要这个,因为我的构建程序设置为拦截警告MSB3270,如果出现则构建失败。此警告表示:“嘿,依赖项中的某些文件格式错误”。但你还记得这个练习的目标吗?我们需要拉取包依赖 DLL。在许多情况下,是否存在此警告并不重要,因为后续构建并不关心。再说一遍,这是我关心的构建程序。因此,我只添加RuntimeIdentifier了在生产构建期间使用的 2 个配置。

完整的后期构建

if not exist "$(ProjectDir)obj\$(ConfigurationName)" mkdir "$(ProjectDir)obj\$(ConfigurationName)"
xcopy  "$(ProjectDir)obj\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)obj\$(ConfigurationName)" /E /R /Y

if $(ConfigurationName) == Release (
    dotnet publish "$(ProjectFileName)" --runtime win-$(PlatformName) --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
) else (
    dotnet publish "$(ProjectFileName)" --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
)

xcopy "$(ProjectDir)pub\my3rdPartyCompany.*.dll" "$(OutDir)" /Y /R
Run Code Online (Sandbox Code Playgroud)

说明:dotnetpublish 正在寻找obj\Debugobj\Release。我们在构建期间没有它,因为构建创建了obj\x64\Releaseobj\x86\Release。第 1 行和第 2 行缓解了这个问题。在第 3 行中,我告诉您dotnet.exe使用特定的配置和目标运行时。否则,当这是调试模式时,我不关心运行时的内容和警告。在最后一行中,我只需将 dll 复制到输出文件夹中即可。任务完成。