简体   繁体   English

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

[英]Disable transitive project reference in .NET Standard 2

I'm writing an MVC website using ASP.NET Core 2.0.我正在使用 ASP.NET Core 2.0 编写一个 MVC 网站。

In the ASP.NET Core project (let's call it Web ), I reference a .NET Standard 2 project in the same solution (let's call it Service ).在 ASP.NET Core 项目(我们称之为Web )中,我在同一个解决方案中引用了一个 .NET Standard 2 项目(我们称之为Service )。 The Service project also references a third .NET Standard 2 library in the solution (let's call this one Business ). Service项目还引用了解决方案中的第三个 .NET Standard 2 库(我们称之为Business )。 The Business project declares a type called Model . Business项目声明了一个名为Model的类型。

The problem is that I can use Model in the Web project (ie the compiler sees the type Model and I can do var a = new Model(); ) as if the Web project has referenced Business , but it actually only has a reference to Service .问题是我可以在Web项目中使用Model (即编译器看到类型Model并且我可以执行var a = new Model(); ),就好像Web项目引用了Business ,但它实际上只引用了Service

How can I hide Model from Web ?如何从Web隐藏Model Is this a new feature in ASP.NET Core 2 or all .NET Standard projects are like this?这是 ASP.NET Core 2 中的新功能还是所有 .NET Standard 项目都是这样?

Edit编辑

As specified here , this is due to transitive project references which is a new "feature" in .NET Standard, but how do I fix it?如此处所述,这是由于传递项目引用造成的,这是 .NET Standard 中的一项新“功能”,但我该如何解决?

Well my question was close to one marked as duplicate here but to solve it requires different tactic.好吧,我的问题接近于此处标记为重复的问题,但要解决它需要不同的策略。

Thanks to comment from "Federico Dipuma" and the answer given here I was able to solve this problem.感谢“Federico Dipuma”的评论和这里给出的答案我能够解决这个问题。

You should edit the Service.csproj file and add PrivateAssets="All" to ProjectReference keys you don't want to flow to top.您应该编辑Service.csproj文件并将PrivateAssets="All"添加到您不想流到顶部的ProjectReference键。

<ItemGroup>
    <ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
</ItemGroup>

Transitive project references ( ProjectReference )可传递项目引用 ( ProjectReference )

Transitive project references are new feature of SDK-style csproj ( 1 , 2 ) format used in .NET Core/.NET >= 5. You can also use this csproj for old .NET Framework projects ( 1 , 2 , 3 ) but with some exceptions .可传递项目引用是 .NET Core/.NET >= 5 中使用的 SDK 样式 csproj ( 1 , 2 ) 格式的新功能。您也可以将此 csproj 用于旧的 .NET Framework 项目( 123 ),但使用一些例外

In this SDK-style format project references (represented by <ProjectReference> entry in .csproj file) are transitive.在此 SDK 样式格式中,项目引用(由 .csproj 文件中的<ProjectReference>条目表示)是可传递的。 This is different to old non-SDK .csproj used previously.这与之前使用的旧的非 SDK .csproj 不同。

But you have three options to go back to old non-transitive behavior.但是你有三个选项可以回到旧的非传递行为。

  1. Use <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> property in .csproj that references projects for which you don't want their transitive dependencies to be visible by compiler.在 .csproj 中使用<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>属性来引用您不希望编译器可见其传递依赖项的项目。

    In your case you can add it to Web project.在您的情况下,您可以将其添加到Web项目中。 (first project that reference other projects, Web -> Service -> Business ) (第一个引用其他项目的项目, Web -> Service -> Business

    You can also set this behavior globally for all .csprojs by doing it in Directory.Build.props file that you put in the root folder that contains your source.您还可以通过在放置在包含源的根文件夹中的Directory.Build.props文件中为所有 .csprojs 全局设置此行为。

     <Project> <PropertyGroup> <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> </PropertyGroup> </Project>

    With this file you basically have old project reference behaviour.使用此文件,您基本上拥有旧的项目参考行为。 Useful when you do migration of old .NET Framework solution that uses old csproj format to new SDK-style .csprojs.当您将使用旧 csproj 格式的旧 .NET Framework 解决方案迁移到新的 SDK 样式 .csprojs 时很有用。

  2. On the project that you reference you can set which dependencies shouldn't flow further when the project is referenced.在您引用的项目上,您可以设置在引用该项目时哪些依赖项不应进一步流动 You use PrivateAssets="All" attribute on <ProjectReference> for this.为此,您可以在<ProjectReference>上使用PrivateAssets="All"属性。 So for example you can edit Service .csproj like this:例如,您可以像这样编辑Service .csproj:

     <ItemGroup> <ProjectReference Include="..\\Business.csproj" PrivateAssets="All" /> </ItemGroup>

    This is more flexible and fine-grained approach.这是一种更灵活和细粒度的方法。 You can control with particular transitive project references should be visible when the project is referenced.当项目被引用时,您可以控制特定的可传递项目引用应该是可见的。

  3. Use ItemDefinitionGroup to define default <PrivateAssets>all</PrivateAssets> metadata for all ProjectReference s.使用ItemDefinitionGroup为所有ProjectReference定义默认的<PrivateAssets>all</PrivateAssets>元数据。 You can also define it in Directory.Build.props file if you want to apply it globally to all projects.如果要将其全局应用于所有项目,也可以在Directory.Build.props文件中定义它。

     <ItemDefinitionGroup> <ProjectReference> <PrivateAssets>all</PrivateAssets> </ProjectReference> </ItemDefinitionGroup>

    The effect would be the same as setting <ProjectReference Include="..."> <PrivateAssets>All</PrivateAssets> </ProjectReference> (or PrivateAssets="All" attribute on all ProjectReferences entries.效果与设置<ProjectReference Include="..."> <PrivateAssets>All</PrivateAssets> </ProjectReference> (或所有ProjectReferences条目的PrivateAssets="All" 属性)相同

    The difference from using 1. approach ( DisableTransitiveProjectReferences ) is that if you explicitly define PrivateAssets metadata on ProjectReference item then this value is used.与使用 1. 方法 ( DisableTransitiveProjectReferences ) 的不同之处在于,如果您在ProjectReference项上明确定义PrivateAssets元数据,则使用此值。 You can think of using ItemDefinitionGroup as a way to provide default value of PrivateAssets metadata it it is not provided explicitly.您可以将ItemDefinitionGroup视为提供PrivateAssets元数据默认值的一种方式,它没有明确提供。

What should you use?你应该用什么? It depends what you prefer.这取决于你喜欢什么。 If you are used to old csproj behavior or want to migrate old solution to .NET Core then using DisableTransitiveProjectReferences or ItemDefinitionGroup in your Directory.Build.props is the easiest solution.如果您习惯了旧的 csproj 行为或想要将旧的解决方案迁移到 .NET Core,那么在Directory.Build.props 中使用DisableTransitiveProjectReferencesItemDefinitionGroup是最简单的解决方案。


Nuget references ( PackageReference ) are also transitive by default.默认情况下,Nuget 引用 ( PackageReference ) 也是可传递的。

This is not strictly answering your question but is something that you should be aware too.这不是严格回答您的问题,而是您也应该注意的事情。

If you are using new PackageReference format for nuget packages (and you probably do because this is the default in new SDK-style csproj files) then you should also be aware that these references are transitive.如果您对 nuget 包使用新的PackageReference格式(您可能会这样做,因为这是新的 SDK 样式的 csproj 文件中的默认格式),那么您还应该注意这些引用是可传递的。 If your project references another project (with ProjectReference ) that references nuget package (with PackageReference ) then your project will also reference this nuget package.如果您的项目引用另一个引用 nuget 包(带有PackageReference )的项目(带有ProjectReference ),那么您的项目也将引用此 nuget 包。

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

Here ProjectA will have implicit reference to Newtosoft.Json library.这里ProjectA将隐式引用Newtosoft.Json库。

Unfortunately there is no DisableTransitivePackagesReferences for package references.不幸的是,没有用于包引用的DisableTransitivePackagesReferences But you can use PrivateAssets metadata like you did for ProjectReference in 2nd option or use ItemDefinitionGroup like you did in 3rd option.但是您可以像在第二个选项中为ProjectReference所做的那样使用PrivateAssets元数据,或者像在第三个选项中那样使用ItemDefinitionGroup

That's why if you want to disable transitive dependencies both for project and package references for all projects then this is how your Directory.build.props file should look like:这就是为什么如果要禁用所有项目的项目和包引用的传递依赖项,那么Directory.build.props文件应如下所示:

<Project>
       <ItemDefinitionGroup>
              <PackageReference>
                     <PrivateAssets>all</PrivateAssets>
              </PackageReference>
              <ProjectReference>
                     <PrivateAssets>all</PrivateAssets>
              </ProjectReference>
       </ItemDefinitionGroup>
</Project>

(source: I learned about this technique from this blog ) (来源:我从这个博客中了解到了这项技术)

All the above answers currently do not work for nuget package dependencies.以上所有答案目前都不适用于 nuget 包依赖项。

For the following library project (PrivateAssets="all"):对于以下库项目 (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>

The following nuspec file will be produced:将生成以下 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>

Notice how "Newtonsoft.Json" is not even specified as a dependency.请注意“Newtonsoft.Json”甚至没有被指定为依赖项。 This will obviously not work as Visual Studio will not even be aware of that dependency and the consuming project will fail to resolved "Newtonsoft.Json" at runtime.这显然不起作用,因为 Visual Studio 甚至不会意识到这种依赖关系,并且使用项目将无法在运行时解析“Newtonsoft.Json”。

The correct answer is setting PrivateAssets="compile" .正确答案是设置PrivateAssets="compile"

Which will result in the following nuspec file:这将产生以下 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>

This will prevent the consuming project from accessing the Newtonsoft.Json namespace in code, while compiling and copying all the required assemblies to allow the "encapsulating" library work.这将阻止消费项目在代码中访问 Newtonsoft.Json 命名空间,同时编译和复制所有必需的程序集以允许“封装”库工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 .NET Standard 项目中“添加服务引用” - How to “Add Service Reference” in .NET Standard project 标准Windows窗体参考.NET Core项目 - Standard Windows Forms reference .NET Core project 在.Net标准2.0项目中添加dll参考 - Adding dll reference in .Net standard 2.0 project 我可以从.NET标准库中引用共享项目吗? - Can I reference a Shared Project from a .NET Standard Library? 如何从 Xamarin iOS 绑定项目引用 .NET 标准库? - How to reference a .NET standard library from a Xamarin iOS binding project? .NET Core,.NET标准和跨解决方案的传递依赖项 - .NET Core, .NET Standard and Transitive Dependencies across Solutions 都引用.NET标准类lib的.NET Windows窗体项目和UWP项目获得: - .NET windows forms project and UWP project that both reference .NET Standard class lib gets: 为什么 .NET 框架项目可以作为参考添加到 .NET 标准 2.0 项目中? - Why .NET framework project can be added as reference in .NET Standard 2.0 project? 如何在.NET Core 2.1项目中引用/导入.NET Standard 2.0类型? - How do you reference/import .NET Standard 2.0 types in a .NET Core 2.1 project? 如何从 a.Net 标准 2.0 添加对 a.Net Core 3.1 项目的引用? - How to add a reference to a .Net Core 3.1 project from a .Net standard 2.0?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM