在 .NET Standard 2 中禁用传递项目引用
Disable transitive project reference in .NET Standard 2
我正在使用 ASP.NET Core 2.0 编写一个 MVC 网站。
在 ASP.NET 核心项目(我们称之为 Web
)中,我在同一解决方案中引用了一个 .NET Standard 2 项目(我们称之为 Service
)。 Service
项目还在解决方案中引用了第三个 .NET Standard 2 库(我们称之为 Business
)。 Business
项目声明了一个名为 Model
.
的类型
问题是我可以在 Web
项目中使用 Model
(即编译器看到类型 Model
而我可以做 var a = new Model();
)就好像Web
项目引用了 Business
,但它实际上只引用了 Service
。
如何向 Web
隐藏 Model
?这是 ASP.NET Core 2 中的新功能还是所有 .NET Standard 项目都是这样?
编辑
根据指定 ,这是由于传递项目引用所致,它是 .NET Standard 中的新 "feature",但我该如何解决它?
好吧,我的问题与此处标记为重复的问题很接近,但要解决它需要不同的策略。
感谢 "Federico Dipuma" 的评论和给出的答案 here 我能够解决这个问题。
您应该编辑 Service.csproj
文件并将 PrivateAssets="All"
添加到 ProjectReference
您不想流到顶部的键。
<ItemGroup>
<ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
</ItemGroup>
传递项目引用(ProjectReference
)
传递项目引用是 SDK 样式 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。
在此 SDK 样式格式中,项目引用(由 .csproj 文件中的 <ProjectReference>
条目表示)是可传递的。这与之前使用的旧非 SDK .csproj 不同。
但是您有三个选项可以返回到旧的非传递行为。
在 .csproj 中使用 <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>
属性 引用您不希望其传递依赖项被编译器可见的项目。
在您的情况下,您可以将其添加到 Web 项目中。 (第一个引用其他项目的项目,Web -> Service -> Business)
您还可以在 Directory.Build.props 文件中为所有 .csprojs 全局设置此行为,该文件位于包含源代码的根文件夹中。
<Project>
<PropertyGroup>
<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>
</PropertyGroup>
</Project>
有了这个文件,您基本上就有了旧的项目引用行为。当您将使用旧 csproj 格式的旧 .NET Framework 解决方案迁移到新 SDK 样式的 .csprojs 时很有用。
在您引用的项目上,您可以设置在引用项目时哪些依赖项不应 进一步流动。为此,您在 <ProjectReference>
上使用 PrivateAssets="All"
属性。例如,您可以像这样编辑 Service.csproj:
<ItemGroup>
<ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
</ItemGroup>
这是一种更灵活、更细粒度的方法。您可以控制特定的传递项目引用在引用项目时应该可见。
使用 ItemDefinitionGroup
为所有 ProjectReference
定义默认 <PrivateAssets>all</PrivateAssets>
元数据。如果你想将它全局应用到所有项目,你也可以在 Directory.Build.props 文件中定义它。
<ItemDefinitionGroup>
<ProjectReference>
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemDefinitionGroup>
效果与在所有 ProjectReferences
条目上设置 <ProjectReference Include="..."> <PrivateAssets>All</PrivateAssets> </ProjectReference>
(或 PrivateAssets="All"
attribute 相同。
与使用 1. 方法 (DisableTransitiveProjectReferences
) 的不同之处在于,如果您在 ProjectReference
项目上明确定义 PrivateAssets
元数据,则会使用此值。您可以考虑使用 ItemDefinitionGroup
作为提供 PrivateAssets
元数据默认值的一种方式,它没有明确提供。
你应该用什么?这取决于你喜欢什么。如果您习惯了旧的 csproj 行为或想将旧的解决方案迁移到 .NET Core,那么在 Directory.Build.props 中使用 DisableTransitiveProjectReferences
或 ItemDefinitionGroup
是最简单的解决方案。
Nuget 引用 (PackageReference
) 默认也是可传递的。
这并没有严格回答您的问题,但您也应该注意这一点。
如果您正在为 nuget 包使用新的 PackageReference
格式(您可能会这样做,因为这是新 SDK 样式的 csproj 文件中的默认格式),那么您还应该知道这些引用是可传递的。如果您的项目引用另一个引用 nuget 包(PackageReference
)的项目(ProjectReference
),那么您的项目也将引用此 nuget 包。
此处 ProjectA 将隐式引用 Newtosoft.Json 库。
不幸的是,有 no DisableTransitivePackagesReferences for package references. But you can use PrivateAssets 元数据,就像您在第二个选项中为 ProjectReference
所做的那样,或者像您在第三个选项中那样使用 ItemDefinitionGroup
。
这就是为什么如果你想禁用所有项目的项目和包引用的传递依赖,那么你的 Directory.build.props 文件应该如下所示:
<Project>
<ItemDefinitionGroup>
<ProjectReference>
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<PackageReference>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemDefinitionGroup>
</Project>
(来源:我从这个 blog 中学到了这个技术)
或
<Project>
<ItemDefinitionGroup>
<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>
<PackageReference>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemDefinitionGroup>
</Project>
以上所有答案目前都不适用于 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>
将生成以下 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>
注意“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>
这将阻止消费项目在代码中访问 Newtonsoft.Json 命名空间,同时编译和复制所有必需的程序集以允许“封装”库工作。
我正在使用 ASP.NET Core 2.0 编写一个 MVC 网站。
在 ASP.NET 核心项目(我们称之为 Web
)中,我在同一解决方案中引用了一个 .NET Standard 2 项目(我们称之为 Service
)。 Service
项目还在解决方案中引用了第三个 .NET Standard 2 库(我们称之为 Business
)。 Business
项目声明了一个名为 Model
.
问题是我可以在 Web
项目中使用 Model
(即编译器看到类型 Model
而我可以做 var a = new Model();
)就好像Web
项目引用了 Business
,但它实际上只引用了 Service
。
如何向 Web
隐藏 Model
?这是 ASP.NET Core 2 中的新功能还是所有 .NET Standard 项目都是这样?
编辑
根据指定
好吧,我的问题与此处标记为重复的问题很接近,但要解决它需要不同的策略。
感谢 "Federico Dipuma" 的评论和给出的答案 here 我能够解决这个问题。
您应该编辑 Service.csproj
文件并将 PrivateAssets="All"
添加到 ProjectReference
您不想流到顶部的键。
<ItemGroup>
<ProjectReference Include="..\Business.csproj" PrivateAssets="All" />
</ItemGroup>
传递项目引用(ProjectReference
)
传递项目引用是 SDK 样式 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。
在此 SDK 样式格式中,项目引用(由 .csproj 文件中的 <ProjectReference>
条目表示)是可传递的。这与之前使用的旧非 SDK .csproj 不同。
但是您有三个选项可以返回到旧的非传递行为。
在 .csproj 中使用
<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>
属性 引用您不希望其传递依赖项被编译器可见的项目。在您的情况下,您可以将其添加到 Web 项目中。 (第一个引用其他项目的项目,Web -> Service -> Business)
您还可以在 Directory.Build.props 文件中为所有 .csprojs 全局设置此行为,该文件位于包含源代码的根文件夹中。
<Project> <PropertyGroup> <DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences> </PropertyGroup> </Project>
有了这个文件,您基本上就有了旧的项目引用行为。当您将使用旧 csproj 格式的旧 .NET Framework 解决方案迁移到新 SDK 样式的 .csprojs 时很有用。
在您引用的项目上,您可以设置在引用项目时哪些依赖项不应 进一步流动。为此,您在
<ProjectReference>
上使用PrivateAssets="All"
属性。例如,您可以像这样编辑 Service.csproj:<ItemGroup> <ProjectReference Include="..\Business.csproj" PrivateAssets="All" /> </ItemGroup>
这是一种更灵活、更细粒度的方法。您可以控制特定的传递项目引用在引用项目时应该可见。
使用
ItemDefinitionGroup
为所有ProjectReference
定义默认<PrivateAssets>all</PrivateAssets>
元数据。如果你想将它全局应用到所有项目,你也可以在 Directory.Build.props 文件中定义它。<ItemDefinitionGroup> <ProjectReference> <PrivateAssets>all</PrivateAssets> </ProjectReference> </ItemDefinitionGroup>
效果与在所有
ProjectReferences
条目上设置<ProjectReference Include="..."> <PrivateAssets>All</PrivateAssets> </ProjectReference>
(或PrivateAssets="All"
attribute 相同。与使用 1. 方法 (
DisableTransitiveProjectReferences
) 的不同之处在于,如果您在ProjectReference
项目上明确定义PrivateAssets
元数据,则会使用此值。您可以考虑使用ItemDefinitionGroup
作为提供PrivateAssets
元数据默认值的一种方式,它没有明确提供。
你应该用什么?这取决于你喜欢什么。如果您习惯了旧的 csproj 行为或想将旧的解决方案迁移到 .NET Core,那么在 Directory.Build.props 中使用 DisableTransitiveProjectReferences
或 ItemDefinitionGroup
是最简单的解决方案。
Nuget 引用 (PackageReference
) 默认也是可传递的。
这并没有严格回答您的问题,但您也应该注意这一点。
如果您正在为 nuget 包使用新的 PackageReference
格式(您可能会这样做,因为这是新 SDK 样式的 csproj 文件中的默认格式),那么您还应该知道这些引用是可传递的。如果您的项目引用另一个引用 nuget 包(PackageReference
)的项目(ProjectReference
),那么您的项目也将引用此 nuget 包。
此处 ProjectA 将隐式引用 Newtosoft.Json 库。
不幸的是,有 no DisableTransitivePackagesReferences for package references. But you can use PrivateAssets 元数据,就像您在第二个选项中为 ProjectReference
所做的那样,或者像您在第三个选项中那样使用 ItemDefinitionGroup
。
这就是为什么如果你想禁用所有项目的项目和包引用的传递依赖,那么你的 Directory.build.props 文件应该如下所示:
<Project>
<ItemDefinitionGroup>
<ProjectReference>
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<PackageReference>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemDefinitionGroup>
</Project>
(来源:我从这个 blog 中学到了这个技术)
或
<Project>
<ItemDefinitionGroup>
<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>
<PackageReference>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemDefinitionGroup>
</Project>
以上所有答案目前都不适用于 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>
将生成以下 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>
注意“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>
这将阻止消费项目在代码中访问 Newtonsoft.Json 命名空间,同时编译和复制所有必需的程序集以允许“封装”库工作。