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

我正在尝试编写一个插件系统。NET 核心,我的要求之一是能够分发的插件 DLL 连同其依赖关系的用户安装。

但是,我不知道如何将 NuGet 依赖项作为构建工件包含在内,并将它们输出到构建文件夹,而不必使用 dotnet publish作为代码。有没有什么方法可以在。Csproj 文件(项目文件) ?

93985 次浏览

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

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

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

您可以使用 PostBuildEvent 在生成时自动化模块部署。

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

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

定义在使用 Include/Excluse (根据需要修改路径)时需要的模块文件

<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 _ off 来回收它,以避免文件出现使用错误。

我用更简单的方法“解决”了这个问题。

在后期建设

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有2.0版本。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。在许多情况下,这个警告是否存在并不重要,因为后续的后期构建并不关心。同样,这是我的构建程序,关心。因此,我只在生产构建期间使用的2个配置中添加了 RuntimeIdentifier

完整的后期建设

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

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

结合上述答案: 在 Visual Studio 的 生成后事件命令行:中,我已经把这个工作得很好了。 它循环遍历所选的 dlls (System * . dll 和 Microsoft.dll) * ,然后跳过删除特定的 dlls。System. Data. SqlClient.dll及 < em > 系统。运行时间。加载器

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

添加

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

没有工作,但添加到 Framework.csproj 文件:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

是的。

我正在使用.NET5,下面是我对类似问题的解决方案。

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

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

解决方案: 修改 Project-A 中 Selenium ChromeDriver NuGet 包引用的属性,只考虑“ contentfiles; analyzer”作为私有资产。如果未指定,则默认值为“ contentfiles; analyzer; build”。这意味着可以将构建的输出文件流到父级引用项目,但不能流到内容文件或分析器,因为“ 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>

之后(在 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>

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

希望这对谁有帮助,祝你好运。