如何获取.NET Core项目以将NuGet引用复制到生成输出?


109

我正在尝试使用.NET Core编写插件系统,而我的要求之一是能够将插件DLL及其依赖项分发给用户进行安装。

但是,我无法弄清楚如何将我的NuGet依赖项作为构建工件包括在内,并将它们输出到构建文件夹中,而不必dotnet publish用作黑客。有什么方法可以在.csproj文件(项目文件)中指定此名称?


2
为什么要使用dotnet publishhack?将命令包含在csproj文件中,作为后期构建脚本。
奥斯汀·德伦斯基

3
dotnet publish将整个框架都放在publish文件夹中,因为我在写插件,所以大多数文件不是必需的,因为该框架已经由bootstrapper程序加载了。我正在寻找类似于.NET Framework上的构建方式的内容。
chyyran'5

并且<CopyToOutputDirectory>Always</CopyToOutputDirectory>要在每个要移动的dll中包含csproj并不能解决问题?也许结合一个<link>节点?
奥斯汀·德伦斯基

7
<PackageReference/>不支持<CopyToOutputDirectory>
chyyran'5

1
“整个框架”来自的NuGet但..如果你选择加入复制所有的NuGet组件来构建输出,你会得到所有的人..
马丁乌尔里希

Answers:


178

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

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

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


7
它会导致复制所有dll,而不仅仅是Nuget dll
Mohammad Dayyan

2
核心2我也正在获取所有Microsoft DLL。不知道为什么,但是在我只得到NuGet之前,它却停止了?烦人
Piotr Kula

4
@MartinUllrich您能详细说明DependencyContext吗?如何使用它查找不在应用程序目录中的DLL?反正呢
ygoe

2
对我来说不起作用asp.net核心不复制System.ValueTuple.dll
Ali Yousefi

1
.net框架项目的@AliYousefie system.valuietuple不再应该来自NuGet的最新.net框架版本和构建工具
Martin Ullrich,

10

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

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

<PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

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

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

将构建文件夹重置为默认文件夹并添加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>

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


在我的项目中,我依赖于Nuget库“ Microsoft.Extensions.Logging.Log4Net.AspNetCore”,并且它不是NetCore的一部分,所以这种方法行不通
sad_robot

4

新增中

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

无效,但是将其添加到Framework .csproj文件中:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

做到了。


当我从.Net Framework 4.7.2项目中引用.net Standard 2.0库时,这对我来说效果很好。没有别的办法修复它。
Grungondola

3

我以更简单的方式“解决”(创建了解决方法)。

在后期制作中

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

pub 是您希望已发布的内容用于分阶段的文件夹

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

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

更新:

上面的设置将在基本调试环境中工作,但需要将其放入构建服务器/生产环境中的情况更多。在这个特殊的例子,我不得不解决的,我们建立Release|x64Release|x86分开。所以我把两者都考虑在内。但是为了支持post build 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>

为什么我需要它,为什么没有它您可以逃脱?我需要这样做,因为我的构建程序设置为拦截警告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

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


如果项目没有调试配置(例如我的情况),则“ dotnet publish”命令需要“ -c Release”参数。因此,我将此批次用作构建后事件: dotnet publish "$(ProjectFileName)" -c Release --no-build -o bin\pub xcopy "$(ProjectDir)pub\PostSharp.dll" "$(OutDir)"
Xtro

0

结合以上答案在Visual Studio 中的Post-build事件命令行中,我的工作非常出色。它遍历选定的dll (System * .dll和Microsoft .dll)*,然后跳过特定dll的删除。System.Data.SqlClient.dllSystem.Runtime.Loader.dll

for %%f in ($(OutDir)System*.dll $(OutDir)Microsoft*.dll) do if not %%f == $(OutDir)System.Data.SqlClient.dll if not %%f == $(OutDir)System.Runtime.Loader.dll del %%f
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.