禁用.NET Standard 2中的传递项目引用

Ema*_*mad 6 c# asp.net-core .net-standard .net-standard-2.0

我正在使用ASP.NET Core 2.0编写MVC网站.

在ASP.NET Core项目中(让我们称之为Web),我在同一个解决方案中引用了.NET Standard 2项目(让我们称之为Service).该Service项目还引用了解决方案中的第三个.NET Standard 2库(让我们称之为Business).该Business项目声明了一个名为的类型Model.

问题是我可以ModelWeb项目中使用(即编译器看到类型Model,我可以做var a = new Model();),就像Web项目已经引用一样Business,但它实际上只有一个引用Service.

如何隐藏ModelWeb?这是ASP.NET Core 2中的新功能还是所有.NET Standard项目都是这样的?

编辑

如此处所述,这是由于传递项目引用,这是.NET Standard中的一个新"功能",但我该如何解决它?

Mar*_*ski 16

传递项目引用 ( ProjectReference)

可传递项目引用是.NET Core/.NET >= 5 中使用的 SDK 样式 csproj ( 1 , 2 ) 格式的新功能。您也可以将此 csproj 用于旧的 .NET Framework 项目(123),但使用一些例外

在此 SDK 样式格式中,项目引用(由<ProjectReference>.csproj 文件中的条目表示)是可传递的。这与之前使用的旧的非 SDK .csproj 不同。

但是你有三个选项可以回到旧的非传递行为。

  1. 使用<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>.csproj 中的属性来引用您不希望编译器可见其传递依赖项的项目。

    在您的情况下,您可以将其添加到Web项目中。(第一个引用其他项目的项目,Web -> Service -> Business

    您还可以通过在放置在包含源的根文件夹中的Directory.Build.props文件中为所有 .csprojs 全局设置此行为。

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

    使用此文件,您基本上拥有旧的项目参考行为。当您将使用旧 csproj 格式的旧 .NET Framework 解决方案迁移到新的 SDK 样式 .csprojs 时很有用。

  2. 在您引用的项目上,您可以设置 在引用该项目时哪些依赖项不应进一步流动。为此,您可以使用PrivateAssets="All"属性 on <ProjectReference>。例如,您可以像这样编辑Service .csproj:

    <ItemGroup>
        <ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
    </ItemGroup>
    
    Run Code Online (Sandbox Code Playgroud)

    这是一种更灵活和细粒度的方法。当项目被引用时,您可以控制特定的可传递项目引用应该是可见的。

  3. 使用ItemDefinitionGroup定义默认<PrivateAssets>all</PrivateAssets>为所有元数据ProjectReference秒。如果要将其全局应用于所有项目,也可以在Directory.Build.props文件中定义它。

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

    效果与设置<ProjectReference Include="..."> <PrivateAssets>All</PrivateAssets> </ProjectReference>(或 所有条目的PrivateAssets="All" 属性)相同ProjectReferences

    与使用 1. 方法 ( DisableTransitiveProjectReferences)的不同之处在于,如果您PrivateAssetsProjectReferenceitem上明确定义元数据,则使用此值。您可以将使用ItemDefinitionGroup视为提供PrivateAssets元数据默认值的一种方式,它没有明确提供。

你应该用什么?这取决于你喜欢什么。如果您习惯了旧的 csproj 行为或想要将旧的解决方案迁移到 .NET Core,那么在Directory.Build.props 中使用 DisableTransitiveProjectReferences或是最简单的解决方案。ItemDefinitionGroup


PackageReference默认情况下,Nuget 引用 ( ) 也是可传递的。

这不是严格回答您的问题,而是您也应该注意的事情。

如果您PackageReference为 nuget 包使用新格式(您可能会这样做,因为这是新的 SDK 样式的 csproj 文件中的默认格式),那么您还应该注意这些引用是可传递的。如果您的项目引用了另一个ProjectReference引用 nuget 包 (with PackageReference) 的项目(with ),那么您的项目也将引用此 nuget 包。

显示 ProjectA 引用 ProjectB 的图表,该 ProjectB 引用了 Newtonsoft.Jon 包

这里ProjectA将隐式引用Newtosoft.Json库。

不幸的是,没有用于包引用的DisableTransitivePackagesReferences。但是您可以像在第二个选项中那样使用PrivateAssets元数据,也ProjectReference可以ItemDefinitionGroup像在第三个选项中那样使用。

这就是为什么如果要禁用所有项目的项目和包引用的传递依赖项,那么Directory.build.props文件应如下所示:

<ItemGroup>
    <ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

(来源:我从这个博客中了解到了这项技术)


Roy*_*bat 11

目前,上述所有答案都不适用于 nuget 包依赖项。

对于以下库项目 (PrivateAssets="all"):

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <Authors>Roy</Authors>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1" PrivateAssets="all" />
  </ItemGroup>

</Project>
Run Code Online (Sandbox Code Playgroud)

将生成以下 nuspec 文件:

<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
  <metadata>
    <id>MyLib</id>
    <version>1.0.0</version>
    <authors>Roy</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package Description</description>
    <dependencies>
      <group targetFramework=".NETStandard2.0" />
    </dependencies>
  </metadata>
</package>
Run Code Online (Sandbox Code Playgroud)

请注意“Newtonsoft.Json”甚至没有被指定为依赖项。这显然不起作用,因为 Visual Studio 甚至不会意识到该依赖关系,并且使用项目将无法在运行时解析“Newtonsoft.Json”。

正确答案是设置PrivateAssets="compile"

这将产生以下 nuspec 文件:

<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
  <metadata>
    <id>MyLib</id>
    <version>1.0.0</version>
    <authors>Roy</authors>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package Description</description>
    <dependencies>
      <group targetFramework=".NETStandard2.0">
        <dependency id="Newtonsoft.Json" version="13.0.1" include="Runtime,Build,Native,ContentFiles,Analyzers,BuildTransitive" />
      </group>
    </dependencies>
  </metadata>
</package>
Run Code Online (Sandbox Code Playgroud)

这将阻止使用项目在代码中访问 Newtonsoft.Json 命名空间,同时编译和复制所有必需的程序集以允许“封装”库工作。

  • 这应该是公认的答案。使用“PrivateAssets=”all“”,运行时会指示缺少库,这个答案解释了原因。 (2认同)

Ema*_*mad 10

好吧,我的问题接近一个标记为重复的问题,但解决它需要不同的策略.

感谢"Federico Dipuma"的评论和这里给出的答案,我能够解决这个问题.

您应该编辑该Service.csproj文件并添加PrivateAssets="All"ProjectReference您不希望流向顶部的键.

<ItemGroup>
    <ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

  • 很好而且很清楚——只是为了强调你所说的(但我第一次设法忽略了)。参考链是 Web-&gt;Services-&gt;Business 并且在 SERVICES 中,您需要添加 PrivateAssets="All" 以从 Web 隐藏业务(我将它放在 Web-&gt;Services ProjectReference 中,但它不起作用 - 我只需要更仔细地阅读您的答案!) (3认同)