How to address (suspected) outdated external package dependencies? - asp.net-core

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>

Related

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.

Build error of ASP.NET Core - "...current settings, version 2.1.0-preview3-26411-06 would be used instead"

I've created a sample project using dotnet, but I get the following error when building the project:
error : The project was restored using Microsoft.NETCore.App version 2.1.0-rc1, but with current settings, version 2.1.0-preview3-26411-06 would be used instead. To resolve this issue, make sure the same settings are used for restore and for subsequent operations such as build or publish. Typically this issue can occur if the RuntimeIdentifier property is set during build or publish but not during restore.
What's the problem? I'm using Visual Studio 2017 build 15.7.0.
I had a similar error message:
The project was restored using Microsoft.NETCore.App version 2.0.7, but with current settings, version 2.0.0 would be used instead. To resolve this issue, make sure the same settings are used for restore and for subsequent operations such as build or publish. Typically this issue can occur if the RuntimeIdentifier property is set during build or publish but not during restore
I added the RuntimeFrameworkVersion setting to the .csproj file, and it fixed an issue for me:
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<RuntimeFrameworkVersion>2.0.7</RuntimeFrameworkVersion><!--here is the fix-->
</PropertyGroup>
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.0.7" />
</ItemGroup>
It seems Visual Studio is using different .NET Core versions for restore/build/publish.
To resolve this issue, you could add TargetLatestRuntimePatch attribute in the .csproj file:
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
</PropertyGroup>
For details, please see this page.
In my case, in the .csproj file I changed
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.0.5" />
</ItemGroup>
to:
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.1.0" />
</ItemGroup>
And it worked.
I’ve installed .NET SDK 2.2.0 and found out that this isn't the correct version and the correct one was renamed to 2.1.300 to be in sync with the .NET Core application whose the last version is 2.1.0. I installed 2.1.300 and everything runs correctly.
Just because you have the latest SDK installed doesn't mean you have the latest runtime installed. I'll never quite understand that.
Run dotnet --info.
I got the following (only the latest installed versions are shown here).
.NET Core SDKs installed:
2.1.300 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:d\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
So I installed 2.1.1 runtime, and now dotnet --info gives me 2.1.1 as well.
Oh and 2.1.3 actually is 2.1.1, but they had to increment it for some reason I don't fully understand about or care about.
I restarted Visual Studio, because it never seems to be able to keep versions in sync
I added the following to PropertyGroup in my .csproj file (unload project + edit)
netcoreapp2.1
2.1.1
Now I thought we didn't need to specify this this any more, and this .csproj file was just created brand new today and it didn't have a runtime version at all. Whatever we're supposed to be doing, this worked for me. I also found this massive thread about versioning with 2.1.1 which I skimmed over, but it seems there are complications with point releases right now, so maybe this specific version is necessary.
I ended up here because of this error:
error : The project was restored using Microsoft.NETCore.App version
2.1.1, but with current settings, version 2.1.0 would be used instead. To resolve this issue, make sure the same settings are used for
restore and for subsequent operations such as build or publish.
Typically this issue can occur if the RuntimeIdentifier property is
set during build or publish but not during restore.
Adding RuntimeFrameworkVersion was the specific fix for that that worked.
Unfortunately there isn't any linked article for this error message, which would be helpful.
Use:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<UserSecretsId>aspnet-...............245435</UserSecretsId>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.1.1" />
</ItemGroup>
</Project>
In my case the issue was fixed by ensuring I had two projects, with one depending on the other.
One project had a RuntimeIdentifier specified in the .csproj file, but the other did not. Once I ensured both had matching RuntimeIdentifiers, the problem was fixed.
The specific error I was getting was
error : NETSDK1061: The project was restored using Microsoft.NETCore.App version 2.0.5, but with current settings, version 2.1.1 would be used instead.
I had
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.0.5" />
</ItemGroup>```
further down the file. Once I removed this and did a clean, the project built successfully.
I have a somehow different solution, working for ASP.NET 2.1, as I had problems with both building and publishing processes:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.0</RuntimeFrameworkVersion> --> fix publishing issues
<PlatformTarget>AnyCPU</PlatformTarget> --> fix publishing issues
</PropertyGroup>
<ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" Version="2.1.0" /> --> fix building issues
<ProjectReference Include="..\PublicSonar.Monitor.Persistent.Json\PublicSonar.Monitor.Persistent.Json.csproj" />
</ItemGroup>
</Project>
I experienced the same:
The project was restored using Microsoft.NETCore.App version 2.1.2, but with current settings, version 2.1.0 would be used instead.
Removing the explicitly set --self-contained false from the dotnet publish command seemed to do the trick for us. It defaults to the same, so why it makes a difference, I have no idea.
This was with SDK version 2.1.400.

MSBuild multiple dll in a single NuGet package

I have a Visual Studio 2017 solution that contains two projects:
Foo.csproj
Foo.Core.csproj
Both of these projects target multiple frameworks: net452;netstandard1.2
Foo.csproj includes a project reference to Foo.Core.csproj:
<ItemGroup>
<ProjectReference Include="..\Foo.Core\Foo.Core.csproj" />
</ItemGroup>
When I generate a NuGet package for Foo.csproj, I want the nupkg file to include both of these assemblies.
What is currently happening is that the NuGet package that gets created has Foo.dll and then a NuGet dependency on Foo.Core (which doesn't exist).
How can I generate a single NuGet package using msbuild that will include both assemblies?
For reference this is the command I am currently using (which is not working how I want it to):
msbuild /p:restore,pack Foo.csproj
This is currently not directly supported by NuGet out of the box. You can follow this GitHub issue for updates.
However, there are a few ways to create such NuGet package.
Use the "Nugetizer 3000"
This is an newly developed tool to build NuGet packages from projects and works by installing the NuGet.Build.Packaging nuget package. You can find some documentation on it on its GitHub wiki page but since it is a very new project, there isn't much documentation or community knowledge around it yet(!) (but the team developing it is very helpful, you could file GitHub issues if you get stuck).
Adding a custom target in the project (2.0.0 tooling / VS 2017 15.3+): Create an item in the csproj that will include the referenced project's output DLL
This approach is very hacky as it relies on an internal MSBuild item that the pack targets use. It works by first marking the <ProjectReference> to not be referenced from the created nuget package like this:
<ProjectReference Include="..\libA\libA.csproj" PrivateAssets="All"/>
Then you can add this to the project to include the generated libA.dll in the nuget package:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2PAssets</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="IncludeP2PAssets">
<ItemGroup>
<BuildOutputInPackage Include="$(OutputPath)\testprivatelib.dll" />
</ItemGroup>
</Target>
Note that this requires you to add all the <PackageReference> items of the referenced project to the project you generate the package from since they would be missing from the generated package since you effectively disabled the transitive reference behaviour.
Create a custom .nuspec file
At the time of writing, this is probably the most "supported" way, but also the most complex. NuGet allows you to disable the automatic generation of the resulting .nuspec file and automatic collection of files by setting the <NuspecFile> property in your project, along with a <NuspecProperties> property that allows you to pass replacement tokens for parsing the .nuspec file.
This works by modifying the project file like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LibB\LibB.csproj" />
</ItemGroup>
<Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
<PropertyGroup>
<NuspecProperties>$(NuspecProperties);id=$(AssemblyName)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);config=$(Configuration)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);authors=$(Authors)</NuspecProperties>
</PropertyGroup>
</Target>
</Project>
This will automatically look for a .nuspec file with the same name as the project (somelib.csproj => somelib.nuspec) and pass some properties along to it. The properties are created in a target in order to be able to access fully resolved and defaulted properties like PackageVersion.
The .nuspec file could look like this:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>$authors$</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<dependencies>
<group targetFramework=".NETStandard1.4">
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
<file src="bin\$config$\netstandard1.4\*.dll" target="lib\netstandard1.4\" />
</files>
</package>
Note that you must add all referenced NuGet packages as a <dependency> element in the .nuspec file since these are no longer automatically generated from the <PackageReference> items in your project file. Refer to the NuSpec Reference for more details.
I have recently created an example project on GitHub demonstrating the use of a custom .nuspec file for exactly this purpose.
The second option that Martin Ullrich mentioned is the only one that works out of the box with .NET Standard that allows to "Generate NuGet package on build" as an integral part of the build.
However like he mentions it has a "hard coded" dependency on a dll with an exact name that you expect to be there (on the output folder) which might bite you in the future. I've found a better alternative which worked for me in .NET Standard without the need of any other modification on this post.
I'll quote it here for completeness.
First you edit your csproj and define the PrivateAssets tag for the reference that you'd like to include:
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
Then you add this to your csproj:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
</ItemGroup>
</Target>
That post also shows how to include the PDBs in the NuGet package option if necessary (which I omitted here).
Been struggling with the same issue and none of the suggested workarounds worked (https://github.com/NuGet/Home/issues/3891) and I couldn't change the csproj to use the new SDK coming with .netcore.
Luckily the nuget pack command comes with the -IncludeReferencedProjects option (ref: https://learn.microsoft.com/en-us/nuget/tools/cli-ref-pack) which does exactly that:
"Indicates that the built package should include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package."
Regardless of the *.nuspec file (not needed here) , add -IncludeReferencedProjects to the pack command and the referenced project dlls will be included along with the nuget dll.
nuget.exe pack yourProject.csproj -IncludeReferencedProjects
I have recently discovered that you CANNOT set defaults for the Nuspec Properties you want to replace in the msbuild command line e.g. if a metadata value is set in the .csproj file of "<Version>2.0.0</Version>" and you run:
msbuild myproject.csproj -t:pack -p:Configuration=Release -p:NuspecProperties=Configuration=Release;PackageVersion=1.2.3
Your .nupgk file will have the version 2.0.0 still. Annoyingly the MS documentation is not clear on this and no error is displayed.

How to add <frameworkAssembly> into nuget package generated from csproj

I'm using VS2017 and the new csproj file format for creating nuget packages.
In my csproj file I have the following:
<ItemGroup>
<Reference Include="System.Net" />
</ItemGroup>
Which works fine (TargetFrameworks == net45) when you build it. But when I pack it in nuget package I want the target package to have it as
<frameworkAssemblies>
<frameworkAssembly assemblyName="System.Net" targetFramework="net45" />
</frameworkAssemblies>
How can I do that with this new tooling?
This is limitation of the current 1.0.* tooling. In the upcoming versions 1.1.* and 2.0.* versions of the ".NET SDK", this will be done automatically, with all <Reference> elements being added as framework assemblies to the resulting NuGet package (unless they are marked with Pack="false"). These changes will also be part of VS 2017 15.3 (not released yet at the time of writing). Note that i am talking about the tools (dotnet --version with SDK installed) version, not the .NET Core runtime versions.
There is a way to use the current preview packages of the pack targets, overriding the ones provided by the SDK - note that this is quite a hacky way and should be removed once you use the new 1.1 or 2.0 tooling.
<Project>
<PropertyGroup>
<NuGetBuildTasksPackTargets>junk-value-to-avoid-conflicts</NuGetBuildTasksPackTargets>
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<!-- All your project's other content here -->
<ItemGroup>
<PackageReference Include="NuGet.Build.Tasks.Pack" Version="4.3.0-preview1-4045" PrivateAssets="All" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>
Also see the related GitHub issue on the NuGet repo where the information for this workaround originated from.