Skip to content

Commit 8072b23

Browse files
authored
[Release/8.0-staging] Reduce net core app current package dependencies (#107161)
* Avoid package dependencies on libraries in the shared framework (#106172) * Avoid package dependencies on libraries in the shared framework We can avoid these dependencies since we can count on the library being part of the shared framework. Fewer dependencies means less packages downloaded, less for customers to service, less copied into the output directory when serviced. * Add warning code. * Address feedback * Add an option to enable servicing for transitive dependencies * Enable all packages that removed dependencies * Add additional packages required for up-stack servicing * Permit settting ServiceTransitiveDependencies in projects as well
1 parent 1d09370 commit 8072b23

File tree

36 files changed

+167
-31
lines changed

36 files changed

+167
-31
lines changed

docs/coding-guidelines/libraries-packaging.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ Source generators and analyzers can be included in the shared framework by addin
1818

1919
Removing a library from the shared framework is a breaking change and should be avoided.
2020

21+
### References to libraries in the shared framework that produce packages
22+
23+
It's beneficial to avoid project references to libraries that are in the shared framework because it makes the package graph smaller which reduces the number of packages that require servicing and the number of libraries that end up being copied into the application directory.
24+
25+
If a dependency is part of the shared framework a project/package reference is never required on the latest version (`NetCoreAppCurrent`). A reference is required for previous .NET versions even if the dependency is part of the shared framework if the project you are building targets .NETStandard and references the project there. You may completely avoid a package dependency on .NETStandard and .NET if it's not needed for .NETStandard (for example - if it is an implementation only dependency and you're building a PNSE assembly for .NETStandard).
26+
27+
Warning NETPKG0001 is emitted when you have an unnecessary reference to a library that is part of the shared framework. To avoid this warning, make sure your ProjectReference is conditioned so that it doesn't apply on `NetCoreAppCurrent`.
28+
2129
## Transport package
2230

2331
Transport packages are non-shipping packages that dotnet/runtime produces in order to share binaries with other repositories.

docs/project/library-servicing.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ If a library is packable (check for the `<IsPackable>true</IsPackable>` property
1616

1717
When you make a change to a library & ship it during the servicing release, the `ServicingVersion` must be bumped. This property is found in the library's source project. It's also possible that the property is not in that file, in which case you'll need to add it to the library's source project and set it to 1. If the property is already present in your library's source project, just increment the servicing version by 1.
1818

19+
## Optionally ensure all up-stack packages are also produced
20+
21+
If you wish to ensure that every package that references a serviced package is also serviced itself, you can enable validation by setting `ServiceTransitiveDependencies` to true. This can be done in an individual project, or globally. When doing this then building the repo, eg: `build libs -allConfigurations` you'll see errors from any project that didn't enable servicing. Reasons for forcing packages which depend on your package to service are security servicing or removing dependencies.
22+
1923
## Test your changes
2024

2125
All that's left is to ensure that your changes have worked as expected. To do so, execute the following steps:

eng/packaging.targets

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,21 @@
196196
</ItemGroup>
197197
</Target>
198198

199+
<Target Name="WarnOnProjectReferenceToFrameworkAssemblies"
200+
BeforeTargets="IncludeTransitiveProjectReferences"
201+
Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' and
202+
'@(ProjectReference)' != ''">
203+
<!-- Find project references that overlap with NetCoreApp, are direct (NuGetPackageId is not set), actually referenced (ReferenceOutputAssembly), and not hidden with PrivateAssets
204+
ProjectReferences can opt out of this checking by setting AllowFrameworkPackageReference, though they should not. -->
205+
<Warning Text="Project reference '%(ProjectReference.Identity)' is a reference to a framework assembly and is not required in $(NetCoreAppCurrent) (NetCoreAppCurrent)."
206+
Code="NETPKG0001"
207+
Condition="$(NetCoreAppLibrary.Contains('%(ProjectReference.Filename);')) and
208+
'%(ProjectReference.ReferenceOutputAssembly)' != 'false' and
209+
'%(ProjectReference.NuGetPackageId)' == '' and
210+
'%(ProjectReference.PrivateAssets)' != 'all' and
211+
'%(ProjectReference.AllowFrameworkPackageReference)' != 'true'" />
212+
</Target>
213+
199214
<Target Name="GenerateMultiTargetRoslynComponentTargetsFile"
200215
Inputs="$(MSBuildProjectFullPath);$(_MultiTargetRoslynComponentTargetsTemplate)"
201216
Outputs="$(MultiTargetRoslynComponentTargetsFileIntermediatePath)">
@@ -303,12 +318,47 @@
303318
</ItemGroup>
304319
</Target>
305320

306-
<Target Name="ValidateServicingVersionIsProperlySet"
321+
<ItemDefinitionGroup>
322+
<TargetPathWithTargetPlatformMoniker>
323+
<!-- When ServiceTransitiveDependencies is set, flow the packaging state -->
324+
<GeneratePackageOnBuild Condition="'$(ServiceTransitiveDependencies)' == 'true'">$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
325+
</TargetPathWithTargetPlatformMoniker>
326+
</ItemDefinitionGroup>
327+
328+
<!-- Flows the list of ProjectReferences that are enabled for packaging when building a multi-targeting project -->
329+
<Target Name="_AddTransitiveServicedPackagesToOutput"
330+
AfterTargets="GetTargetPathWithTargetPlatformMoniker"
331+
Condition="'$(IsInnerBuild)' == 'true'">
332+
<PropertyGroup>
333+
<_TransitiveServicedPackages
334+
Condition="'%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' and
335+
'%(ReferencePath.GeneratePackageOnBuild)' == 'true'"
336+
>@(ReferencePath->'%(OriginalProjectReferenceItemSpec)')</_TransitiveServicedPackages>
337+
</PropertyGroup>
338+
<ItemGroup>
339+
<TargetPathWithTargetPlatformMoniker TransitiveServicedPackages="$(_TransitiveServicedPackages)" />
340+
</ItemGroup>
341+
</Target>
342+
343+
<!-- Validate that ServicingVersion is set and packing is enabled. Runs once in the outer build (or only build if no outer build exists). -->
344+
<Target Name="ValidateServicingProperties"
307345
Condition="'$(PreReleaseVersionLabel)' == 'servicing' and
308346
'$(PackageUseIncrementalServicingVersion)' == 'true' and
309-
'$(DotNetBuildFromSource)' != 'true'"
310-
AfterTargets="GenerateNuspec">
311-
<Error Condition="'$(ServicingVersion)' == '0'" Text="ServicingVersion is set to 0 and it should be an increment of the patch version from the last released package." />
347+
'$(DotNetBuildFromSource)' != 'true' and
348+
'$(IsInnerBuild)' != 'true'"
349+
AfterTargets="Build">
350+
<ItemGroup>
351+
<TransitiveServicedPackages Include="%(InnerOutput.TransitiveServicedPackages)" Condition="'$(IsCrossTargetingBuild)' == 'true'" />
352+
<TransitiveServicedPackages Include="'%(ReferencePath.OriginalProjectReferenceItemSpec)"
353+
Condition="'%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' and
354+
'%(ReferencePath.GeneratePackageOnBuild)' == 'true'" />
355+
</ItemGroup>
356+
<Error Condition="'$(ServicingVersion)' == '0' and '$(GeneratePackageOnBuild)' == 'true'"
357+
Text="ServicingVersion is set to 0 and it should be an increment of the patch version from the last released package." />
358+
359+
<Error Condition="'$(GeneratePackageOnBuild)' != 'true' and
360+
'@(TransitiveServicedPackages)' != ''"
361+
Text="This project did not set GeneratePackageOnBuild, but dependencies '@(TransitiveServicedPackages)' did. Please ship this project by setting GeneratePackageOnBuild to true and incrementing ServicingVersion." />
312362
</Target>
313363

314364
</Project>

src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
55
<EnableDefaultItems>true</EnableDefaultItems>
66
<IsPackable>true</IsPackable>
7+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
8+
<ServicingVersion>1</ServicingVersion>
79
<PackageDescription>In-memory cache implementation of Microsoft.Extensions.Caching.Memory.IMemoryCache.</PackageDescription>
810
</PropertyGroup>
911

src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
66
<EnableDefaultItems>true</EnableDefaultItems>
77
<IsPackable>true</IsPackable>
8+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
9+
<ServicingVersion>1</ServicingVersion>
810
<PackageDescription>JSON configuration provider implementation for Microsoft.Extensions.Configuration. This package enables you to read your application's settings from a JSON file. You can use JsonConfigurationExtensions.AddJsonFile extension method on IConfigurationBuilder to add the JSON configuration provider to the configuration builder.</PackageDescription>
911
</PropertyGroup>
1012

@@ -13,9 +15,12 @@
1315
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Configuration.Abstractions\src\Microsoft.Extensions.Configuration.Abstractions.csproj" />
1416
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Configuration.FileExtensions\src\Microsoft.Extensions.Configuration.FileExtensions.csproj" />
1517
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.FileProviders.Abstractions\src\Microsoft.Extensions.FileProviders.Abstractions.csproj" />
16-
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.Json\src\System.Text.Json.csproj" />
1718
<Compile Include="$(CommonPath)System\ThrowHelper.cs"
1819
Link="Common\System\ThrowHelper.cs" />
1920
</ItemGroup>
2021

22+
<ItemGroup Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)'">
23+
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.Json\src\System.Text.Json.csproj" />
24+
</ItemGroup>
25+
2126
</Project>

src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
55
<EnableDefaultItems>true</EnableDefaultItems>
66
<IsPackable>true</IsPackable>
7+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
8+
<ServicingVersion>1</ServicingVersion>
79
<PackageDescription>User secrets configuration provider implementation for Microsoft.Extensions.Configuration. User secrets mechanism enables you to override application configuration settings with values stored in the local secrets file. You can use UserSecretsConfigurationExtensions.AddUserSecrets extension method on IConfigurationBuilder to add user secrets provider to the configuration builder.</PackageDescription>
810
</PropertyGroup>
911

src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
55
<EnableDefaultItems>true</EnableDefaultItems>
66
<IsPackable>true</IsPackable>
7+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
8+
<ServicingVersion>1</ServicingVersion>
79
<PackageDescription>XML configuration provider implementation for Microsoft.Extensions.Configuration. This package enables you to read configuration parameters from XML files. You can use XmlConfigurationExtensions.AddXmlFile extension method on IConfigurationBuilder to add XML configuration provider to the configuration builder.</PackageDescription>
810
</PropertyGroup>
911

@@ -24,7 +26,7 @@
2426
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">
2527
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresDynamicCodeAttribute.cs" />
2628
</ItemGroup>
27-
29+
2830
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
2931
<Reference Include="System.Security" />
3032
</ItemGroup>

src/libraries/Microsoft.Extensions.DependencyModel/src/Microsoft.Extensions.DependencyModel.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
44
<EnableDefaultItems>true</EnableDefaultItems>
55
<IsPackable>true</IsPackable>
6-
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
7-
<ServicingVersion>1</ServicingVersion>
6+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
7+
<ServicingVersion>2</ServicingVersion>
88
<PackageDescription>Provides abstractions for reading `.deps` files. When a .NET application is compiled, the SDK generates a JSON manifest file (`&lt;ApplicationName&gt;.deps.json`) that contains information about application dependencies. You can use `Microsoft.Extensions.DependencyModel` to read information from this manifest at run time. This is useful when you want to dynamically compile code (for example, using Roslyn Emit API) referencing the same dependencies as your main application.
99

1010
By default, the dependency manifest contains information about the application's target framework and runtime dependencies. Set the PreserveCompilationContext project property to `true` to additionally include information about reference assemblies used during compilation.</PackageDescription>
@@ -22,18 +22,18 @@ By default, the dependency manifest contains information about the application's
2222
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
2323
<Compile Remove="**\*.netstandard.cs" />
2424
</ItemGroup>
25-
25+
2626
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
2727
<Compile Remove="**\*.netcoreapp.cs" />
2828
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresAssemblyFilesAttribute.cs" />
2929
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\UnconditionalSuppressMessageAttribute.cs" />
3030
</ItemGroup>
3131

3232
<ItemGroup>
33-
<InternalsVisibleTo Include="Microsoft.Extensions.DependencyModel.Tests" />
33+
<InternalsVisibleTo Include="Microsoft.Extensions.DependencyModel.Tests" />
3434
</ItemGroup>
3535

36-
<ItemGroup>
36+
<ItemGroup Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)'">
3737
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.Encodings.Web\src\System.Text.Encodings.Web.csproj" />
3838
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.Json\src\System.Text.Json.csproj" />
3939
</ItemGroup>
@@ -46,5 +46,5 @@ By default, the dependency manifest contains information about the application's
4646
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
4747
<Reference Include="System.Runtime" />
4848
</ItemGroup>
49-
49+
5050
</Project>

src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Microsoft.Extensions.Diagnostics.Abstractions.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
55
<EnableDefaultItems>true</EnableDefaultItems>
66
<IsPackable>true</IsPackable>
7+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
8+
<ServicingVersion>1</ServicingVersion>
79
<!-- Disabling baseline validation since this is a brand new package.
810
Once this package has shipped a stable version, the following line
911
should be removed in order to re-enable validation. -->
@@ -31,8 +33,11 @@ Microsoft.Extensions.Diagnostics.Metrics.MetricsOptions</PackageDescription>
3133
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\DynamicallyAccessedMemberTypes.cs" />
3234
</ItemGroup>
3335

34-
<ItemGroup>
36+
<ItemGroup Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)'">
3537
<ProjectReference Include="$(LibrariesProjectRoot)System.Diagnostics.DiagnosticSource\src\System.Diagnostics.DiagnosticSource.csproj" />
38+
</ItemGroup>
39+
40+
<ItemGroup>
3641
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.DependencyInjection.Abstractions\src\Microsoft.Extensions.DependencyInjection.Abstractions.csproj" />
3742
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Options\src\Microsoft.Extensions.Options.csproj" />
3843
</ItemGroup>

src/libraries/Microsoft.Extensions.Diagnostics/src/Microsoft.Extensions.Diagnostics.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
should be removed in order to re-enable validation. -->
99
<DisablePackageBaselineValidation>true</DisablePackageBaselineValidation>
1010
<IsPackable>true</IsPackable>
11+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
12+
<ServicingVersion>1</ServicingVersion>
1113
<PackageDescription>This package includes the default implementation of IMeterFactory and additional extension methods to easily register it with the Dependency Injection framework.</PackageDescription>
1214
</PropertyGroup>
1315

0 commit comments

Comments
 (0)