如何使用 csproj 多目标 .NET Core 类库?

Posted

技术标签:

【中文标题】如何使用 csproj 多目标 .NET Core 类库?【英文标题】:How do you multi-target a .NET Core class library with csproj? 【发布时间】:2017-03-12 13:26:54 【问题描述】:

当 .NET Core 仍然使用 project.json 格式时,您可以构建一个类库 targeting multiple frameworks(例如 net451、netcoreapp1.0)。

既然官方的项目格式是csproj使用MSBuild,那么如何指定多个框架来定位呢?我正在尝试从 VS2017 中的项目设置中查找此内容,但我只能针对 .NET Core 框架中的单个框架(它甚至没有列出我所做的其他完整 .NET Framework 版本) 已安装):

【问题讨论】:

这不是它应该看起来的样子,你应该得到下拉列表中列出的 .NETStandard 1.x 选项。目前还不是很清楚这是怎么发生的,一定要选择正确的项目模板来开始。应该是“类库(.NET 标准)”。看起来您选择了控制台应用程序模板,然后开始更改属性,而不是正确的方式。如果您实际上使用了类库模板,那么安装并不顺利。 我实际上选择了类库(.NET Core)。 对,如果你想多目标,那就错了。您必须选择一个 .NETStandard 才能使该库在多个平台上可用。 这就清除了。如果你愿意,你可以写出你的 cmets 的答案。 【参考方案1】:

您需要手动编辑项目文件并将s添加到默认的TargetFramework中,基本上将其更改为TargetFrameworks。然后你提到 Moniker 带有 ; 分隔符。

您还可以手动或使用 VS Nuget 包管理器将 Nuget 包引用放入条件 ItemGroup。

你的 .csproj 应该是这样的:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard1.6;net452</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'net452'">
    <PackageReference Include="Microsoft.Azure.DocumentDB">
      <Version>1.12.0</Version>
    </PackageReference>
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.6'">
    <PackageReference Include="Microsoft.Azure.DocumentDB.Core">
    <Version>1.1.0</Version>
    </PackageReference>
  </ItemGroup>
</Project>

由于缺少文档,这些天我做的另一个解决方法是我在 VS2015 中创建一个项目并使用可用文档和智能感知形成 project.json,然后在 VS2017 中打开解决方案并使用内置升级。然后,我将查看 csproj 文件以了解如何进行该配置。

在没有Moniker的情况下多定位更深奥的目标:

微软:

不推荐使用 PCL+

虽然支持 PCL,但包作者应该支持 而是使用网络标准。 .NET 平台标准是 PCL 表示跨平台的二进制可移植性,使用单个 不与诸如便携式 a+b+c 名称之类的静态绑定的名称。

如果您想定位便携式配置文件,它没有预定义的绰号,因此便携式配置文件也无法推断出TargetFrameworkIdentifierTargetFrameworkVersionTargetFrameworkProfile。编译器常量也不会自动定义。最后,您必须添加默认情况下不提供的所有程序集引用。

下面的这个示例取自一个使用dynamic 关键字的项目,因此它还需要Microsoft.CSharp 程序集,因此您可以看到它对不同目标的引用。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard1.5;net40;portable40-net45+sl5+win8+wp8</TargetFrameworks>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
    <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <TargetFrameworkProfile>Profile158</TargetFrameworkProfile>
    <DefineConstants>$(DefineConstants);PORTABLE158</DefineConstants>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='netstandard1.5'">
    <PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
    <PackageReference Include="System.ComponentModel" Version="4.3.0" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='net40'">
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Windows" />
  </ItemGroup>
</Project>

【讨论】:

你必须通过手动编辑csproj来做到这一点,还是可以通过VS来完成? @Gigi 多目标需要手动完成。 Nuget 包可以通过 VS2017 或手动完成。 我遇到了同样的问题,在我将 s 添加到 后一切正常。真希望这些事情得到更好的记录。 @AsadSaeeduddin 可能是 Resharper 向您展示了曲线而不是 Visual Studio。 $(TargetFramework) 仅用于使 ItemGroup 可用于特定框架/Moniker。 @O.R.Mapper 如果 NuGet 包构造正确,这应该在您导入时自动发生。这意味着如果 NuGetPackageA 已经支持多个框架,则无需将其放入条件项组中。现在,如果您需要为 .net 框架引用 PackageA,为 .net 核心引用 PackageB,则需要将其放入条件项组中。截至今天(2017 年 10 月),界面中没有选项。【参考方案2】:

您可以为此手动编辑.csproj 文件并设置TargetFrameworks(不是TargetFramework)属性。

<TargetFrameworks>net451;netstandard1.4</TargetFrameworks>

例如见EFCore.csproj: https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj

【讨论】:

谢谢!它杀了我。在 40 年前 Brian Kernigan 的“编程风格的要素”中,他谈到了使用末尾有一个字母不同的变量的错误。如果名称是“TargetFrameworkList”会更清楚。 您指向的示例不包含 属性。 @RenniePet,谢谢!项目文件已及时更改。我将链接更改为具体提交,其中有 .【参考方案3】:

我实际上选择了类库 (.NET Core)。

如果您的库需要在多个平台目标上工作,那不是您想要的项目模板。使用此项目模板,您的库只能在以 .NETCore 为目标的项目中使用。 PCL 库方法已停用,您现在必须选择 .NETStandard。

您可以通过使用“类库(.NET 标准)”项目模板启动项目来做到这一点。您现在可以选择 .NETStandard 版本。当前的兼容性网格is here。

希望他们会更新链接的文章。这是不断变化的,.NETStandard 2.0 已确定但尚未发布。目标是 2017 年第二季度,可能是春末,目前显示已完成 97%。我无意中听到设计师说不推荐使用1.5或1.6,与2.0不够兼容

【讨论】:

如果你对不同的目标框架有不同的依赖关系,它是如何工作的?我的意思是在project.json 中,您可以为目标框架指定特定的依赖项。 我 90% 确定您需要忘记这曾经存在过。这是一个令人困惑的混乱,只是引导 .NETCore 的权宜之计。使用我链接到的兼容性网格。 我也很怀疑。非常感谢您的澄清! @HansPassant 多目标仍然是最好的选择,如果你有遗留代码,同时你的新开发可以在最近的完整框架风格或 dotnetcore 中完成。 甚至还不一定对 .NET Core 友好。我正在使用 Azure Function Apps,但它们的 .NET Core 版本仅支持几个触发器。 (我需要服务总线触发器,所以我被 .NET 框架困住了,而且一个非常大的业务功能库可能最终成为多目标。)微软的平台现在是一团糟。它是现代版的 DLL Hell。【参考方案4】:

我做了一个simple guide to multi-targeting net framework and netcore,它从最短 15 秒的修复开始,然后引导您完成每个复杂问题。

最简单的方法是:

    首先, 让 netcore 或 netstandard 目标正常工作。

然后

    编辑 .csproj 项目文件并为其他目标完成这些步骤。

      &lt;TargetFramework&gt; 标记更改为&lt;TargetFrameworks&gt; 并将您的下一个目标添加到列表中,由; 分隔 了解 csproj 文件中的条件部分。为每个目标创建一个。使用它们来声明每个目标的依赖关系。 只需阅读构建错误消息中缺少的内容,即可为任何网络框架目标的 System.* dll 添加 &lt;Reference /&gt;s。 处理 NuGet &lt;PackageReference /&gt;s 依赖项在它们对于每个目标不相同的情况下。 (这里最简单的技巧是暂时恢复为单一目标,以便 GUI 为您正确处理 Nuget 引用)。 如果你必须:学习各种创造性的技术、变通方法和节省时间的方法来处理不能在所有目标上编译的代码。 当添加更多目标的成本太高时,知道何时减少损失。

【讨论】:

以上是关于如何使用 csproj 多目标 .NET Core 类库?的主要内容,如果未能解决你的问题,请参考以下文章

为 .NET Core 项目 - CSPROJ - 而不是 JSON 项目设置版本号

[.NET Core 24]把project.json迁移到.csproj

如何在 .NET Core 3.0 SDK 上构建多目标 .NET 5 和 .NET Core 3.1

.net core 项目如何知道构建时要包含哪些文件

将Visual Studio项目转换为Dot Net Core项目 csproj to xproj

将NuGet构建工具包与ASP.NET Core一起使用