Why is it recommended for Meta Packages to rely on the implicit version specified by the SDK? - asp.net-core

I want to understand why Microsoft recommends not to specify an explicit version for Meta Package.
I am new to dot net core and I am trying to understand the importance of implicit versioning with respect to Meta Packages in web.config file.
I also went through github discussion about the implicit version. But I didn't understand much.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" />
</ItemGroup>
</Project>
I wanted to know what are the disadvantages of mentioning version explicitly in the above code?

Related

How to address (suspected) outdated external package dependencies?

We have a .Net Core 6.0 solution and two of the projects have NuGet package references set to Azure.Storage.Blobs 12.14.1 (the latest version at the time of writing):
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.14.1" />
</ItemGroup>
Today a new security scanning tool that IT are testing flagged up a "critical" issue:
System.Text.Encodings.Web Remote Code Execution (RCE) CVE-2021-26701
CVSS 9.8 Critical
Introduced through: project
› Azure.Storage.Blobs 12.14.1
› System.Text.Json 4.7.2
› System.Text.Encodings.Web 4.7.1
I looked at the nuget.org page for Azure.Storage.Blobs and it shows System.Text.Json (>= 4.7.2) which implied to me (perhaps wrongly) that Blobs should work just fine with later versions of Encodings.Web:
I'm only referencing Azure.Storage.Blobs, so does this mean that Azure.Storage.Blobs itself is referencing an out-of-date package?
I'm keen to avoid creating my own dependency on the nested packages when they're not directly used. My research showed that NPM has a way around these issues, but I've been unable to find a NuGet-based solution.
Can anyone please explain what the solution is to ensure that my dependencies are kept secure here?
Central package management offers a feature called transitive pinning to manage (the versions of) transitive/indirect dependencies, without making them direct dependencies.
From the documentation
Starting with NuGet 6.2, you can centrally manage your dependencies in your projects with the addition of a Directory.Packages.props file and an MSBuild property.
You can automatically override a transitive package version even without an explicit top-level by opting into a feature known as transitive pinning. This promotes a transitive dependency to a top-level dependency implicitly on your behalf when necessary.
First enable central package management.
Add a Directory.Packages.props file to e.g. the root of your repository (near your .sln file).
Set ManagePackageVersionsCentrally to true.
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
Include any direct NuGet packages using PackageVersion tags; notice the difference with PackageReference tags.
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Azure.Storage.Blobs" Version="12.14.1" />
</ItemGroup>
</Project>
Adjust your .csproj file(s) by removing the version indication from any PackageReference tags since this will now be managed centrally, although you can still override if needed.
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" />
</ItemGroup>
</Project>
Next enable transitive pinning by setting ManagePackageVersionsCentrally to true.
Add below tag in a PropertyGroup.
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
Then include the concerning packages.
In your case you can e.g. upgrade and pin System.Text.Json or System.Text.Encodings.Web to a higher version, e.g.:
<PackageVersion Include="System.Text.Json" Version="6.0.7" />
You need to figure out which version applies for your concrete case.
Full Directory.Package.props example.
The transitive dependencies don't need to be in a separate ItemGroup, but it might be more insightful.
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Azure.Storage.Blobs" Version="12.14.1" />
</ItemGroup>
<!-- Transitive packages -->
<ItemGroup>
<PackageVersion Include="System.Text.Json" Version="6.0.7" />
</ItemGroup>
</Project>

How to use SatelliteResourceLanguages to filter out resource files when publishing .NET Core API services

When publishing .NET Core API services, the output includes with localized resources (cs, de, es, fr, etc.)
Searching for a solution to prevent .NET Core from publishing these localized resource files, I came across this commit on Github to implement SatelliteResourceLanguages for that purpose.
But how can I implement it?
According to this answer, you should just add it to the project file:
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
Here's how you can use the above line in a project config:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<SatelliteResourceLanguages>en;de;pt</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FooBar" Version="2.0.1" />
</ItemGroup>
</Project>
Note that I couldn't find SatelliteResourceLanguages documented officially anywhere as of today.
Also note that you need to have a recent version of the SDK, as this bug report mentions that a typo prevented this to work properly in prior releases.

Is there an equivalent of $(BuildingInsideVisualStudio) which will detect NuGet?

In MSBuild there is a variable $(BuildingInsideVisualStudio) which can be used to detect whether build is running inside Visual Studio, so I can do conditions like this:
<PropertyGroup Condition="'$(BuildingInsideVisualStudio)' != 'true'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
Is there anything similar for NuGet? I want different conditions to run if the project is being used inside package manager.
Your comment to the question makes it sound like your goal is to keep a packages versions consistent across different conditions in a single project, but it's also a common case that you want to keep it consistent across projects in a solution or repo.
I'm going to suggest a different solution. Create a Directory.Build.props in your repo root that looks something like this:
<Project>
<PropertyGroup>
<NewtonsoftJsonVersion>12.0.1</NewtonsoftJsonVersion>
<xunitVersion>2.4.1</xunitVersion>
</PropertyGroup>
</Project>
Now in your projects that need Newtonsoft.json, you change the PackageReference to <PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonVersion)" />.
If you put your production code in src\ and test code in test\, then you can create a test\Directory.Build.props with the contents:
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<PackageReference Include="xunit" Version="$(xunitVersion)" />
</PropertyGroup>
</Project>
Now all of your projects under test\ will get xunit automatically, and it's guaranteed to be the same version.
When you want to upgrade a package version, you can use the Package Manager UI to check for versions, but unfortunately not to upgrade the version. For that, you'll need to manually edit the repo root Directory.Build.props (so add it to your solution for quick access), but you can be confident that every reference to that package will use the same version. It is limited to projects using PackageReference, there's no solution currently for packages.config, but MSBuild conditions only for for PackageReference too.
You can see this pattern often in Microsoft repositories. Certainly NuGet (my team, yay!), and various .NET repos like cli and sdk do it, although in manually imported props files, rather than Directory.Build.props, though the concept is the same.
There is no direct solution for the case. NuGet is just download manager, it loads sources. MSBuild is a build system, it builds sources. They don't exchange any information between.
I would suggest you to move an another way. You can add a props file into your nuget packaging project with
<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<ItemGroup>
<PackageUsedFromNuget>true</PackageUsedFromNuget>
</ItemGroup>
</Project>

What is the default version of the nuget package when referenced with PackageReference in .NET Core project?

I am trying to learn and understand nuget and msbuild in .NET Core by examining and manually editing project files (.csproj in .NET Core 2.2).
So when I create WebApi project, the .csproj file looks like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
</ItemGroup>
</Project>
Notice that there is no Version attribute specified for the first PackageReference.
Now if I specify it to be the latest stable version 2.2.3 like this:
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.3" />
I get build warning NETSDK1071 which says:
A PackageReference to 'Microsoft.AspNetCore.App' specified a Version
of 2.2.3. Specifying the version of this package is not recommended.
For more information, see https://aka.ms/sdkimplicitrefs
This warning is not shown when Version attribute is omitted so I was wondering how is nuget package Version resolved when not set explicitly?
Also, how does dotnet build knows which version of a nuget package is recommended with the current project settings?
From the link in the warning, you can learn that it is not a regular package, but Meta-package.
It's mean that this package depends on your TargetFramework, and this is mean that when you target to a specific framework that installed in your machine (as SDK), the package will be taken from the specific SDK.

StackExchange.Redis.StrongName is refrenced but not included as package

I'm starting a new project using StackExchange.Redis and .Net Core 2.0.
But I get a conflict:
The type 'ConnectionMultiplexer' exists in both 'StackExchange.Redis.StrongName, Version=1.2.4.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46' and 'StackExchange.Redis, Version=1.2.6.0, Culture=neutral, PublicKeyToken=null'
Why is this showing even thou I'm not referencing StackExchange.Redis.StrongName and it's not even the same assembly version?
I found my solution here.
By adding this (below) to my csproj:
<Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'StackExchange.Redis.StrongName'">
<Aliases>signed</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
It is possible to use Strongname in your entire application, 1.2.6 is newer and will be used. The problem is when you add Redis.Stackexchange you will have the same namespace from two different dll's. .Net compiler doesn't know which one to use. If you need 1.2.6, use the StrongName version throughout your application and no more problems ....
I added a conditional flag to the "StackExchange.Redis" package, that makes it work. I Tried this solution on two new projects on two machines. Don't ask me why it works tho.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="StackExchange.Redis" Version="1.2.6" />
</ItemGroup>
</Project>
Microsoft.Extensions.Caching.Redis 2.0 that ships with Asp .Net Core 2.0 internally uses StackExchange.Redis.StrongName, Version=1.2.4.0, that there is for example in C:\Program Files\dotnet\sdk\NuGetFallbackFolder\stackexchange.redis.strongname\1.2.4\lib\netstandard1.5 folder.
So looks it's causes a conflict between different versions of StackExchange.Redis.