question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Transitive FrameworkReference interfere with VS restore causing project system to nominate again and cause extra restores

See original GitHub issue

@nkolev92 commented on Thu Nov 19 2020

Visual Studio Version: 16.9 P1 (repros with 16.8, I’d expect it repros all the way down to 16.3)

Summary:

Take a project that has a package that has a framework reference not set in the project. That project starts with Microsoft.NETCore.App reference. After the first restore happens in VS, the project transitively inherits Microsoft.AspNetCore.App. Project-system this. This shouldn’t happen, only direct FrameworkReference should be nominated.

Steps to Reproduce:

  1. Checkout https://github.com/nkolev92/ProjectWithTransitiveFrameworkReference.

  2. Enable project system logging with $env:CPS_DiagnosticRuntime=1

  3. Do not restore/build. Load the solution in Visual Studio.

  4. Observe that restore happens twice. Observe that nomination has happened twice.

  5. If you inspect the nomination data you will see that 1st nomination is something like:

BEGIN Nominate Restore for C:\Users\Roki2\Documents\Code\ProjectWithTransitiveFrameworkReference\ConsoleApp\ConsoleApp.csproj
    MSBuildProjectExtensionsPath:     C:\Users\Roki2\Documents\Code\ProjectWithTransitiveFrameworkReference\ConsoleApp\obj\
    OriginalTargetFrameworks:         
    Target Frameworks (1)
        .NETCoreApp,Version=v5.0
            Framework References
                Microsoft.NETCore.App -- (PrivateAssets:All)
            Package Downloads
            Project References
            Package References

but the 2nd one has:

BEGIN Nominate Restore for C:\Users\Roki2\Documents\Code\ProjectWithTransitiveFrameworkReference\ConsoleApp\ConsoleApp.csproj
    MSBuildProjectExtensionsPath:     C:\Users\Roki2\Documents\Code\ProjectWithTransitiveFrameworkReference\ConsoleApp\obj\
    OriginalTargetFrameworks:         
    Target Frameworks (1)
        .NETCoreApp,Version=v5.0
            Framework References
                Microsoft.AspNetCore.App -- (PrivateAssets:)
                Microsoft.NETCore.App -- (PrivateAssets:All)
            Package Downloads
            Project References
            Package References

This happens because the project has a package that transitively pulls in the AspNet FrameworkReference.

Expected Behavior:

Only one nomination, thus one restore has happened. The restore should not impact the data being sent to NuGet.

Note that commandline restores similar to the first restore.

Actual Behavior:

After the initial restore, a 2nd nomination comes in with additional FrameworkReference data. This causes an extra restore.

User Impact:

Performance, delays solution load. Note that this also makes commandline restore outputs dirty, so restore would be more expensive.

cc @panopticoncentral @davkean @lifengl

Ran into while trying to test bulk file tests. I had also been observing some weird restore counts in NuGet’s RPS tests, and I think this partially explains those.


@davkean commented on Thu Nov 19 2020

We call a target provided by NuGet; CollectFrameworkReferences. This is outside our control.


@nkolev92 commented on Fri Nov 20 2020

NuGet uses that target on the commandline too. It always returns only 1 value, not 2. Regardless whether the assets file exists or not. So there’s something different about VS that I don’t understand.

CollectFrameworkReferences

cc @dsplaisted maybe he has some ideas.


@davkean commented on Fri Nov 20 2020

The thing that turns framework references in packages/assets file into real framework references will be running alongside the CollectFrameworkReferences in VS. they aren’t isolated.


@nkolev92 commented on Fri Nov 20 2020

they aren’t isolated

That’s what I feared. We need to differentiate between them somehow.

Given that packages are rarely shipped through a VS restore/build/pack, I’m not too worried about potential bad packages getting created, but the performance impact of double restores is there.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.0" />
  </ItemGroup>

  <Target Name="CheckRefs" BeforeTargets="Build">
    <CallTarget Targets="CollectFrameworkReferences" />
  </Target>
</Project>

Given that this runs the target at build time, if you generate a binlog, 2 framework references are shown.

The framework ref is being added in https://github.com/dotnet/sdk/blob/44f381b62d466565639d51847c9127afbe7062a9/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets#L154-L161.

One idea is:

  • AddTransitiveFrameworkReferences should add some metadata to the FrameworkReference.
  • CollectFrameworkReferences will ensure it skips items with that metadata.

Any other ideas?

I’ll move this to SDK side.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
dsplaistedcommented, Dec 3, 2020

@sfoslund Would you be able to add a test case for this? It will need the fix from NuGet to flow in.

1reaction
dsplaistedcommented, Nov 20, 2020

@nkolev92 Your suggestion to distinguish these with metadata sounds good. However, since the CollectFrameworkReferences target is in NuGet.targets, we’d need both an SDK and a NuGet change.

We could update the AddTransitiveFrameworkReferences target to do this:

   <ItemGroup> 
     <FrameworkReference Include="@(TransitiveFrameworkReference)" Exclude="@(FrameworkReference)"
                         IsTransitiveFrameworkReference="true" /> 
   </ItemGroup> 

Then the NuGet target would look something like this:

<Target Name="CollectFrameworkReferences" Returns="@(_FrameworkReferenceForRestore)">
    <ItemGroup>
        <_FrameworkReferenceForRestore Include="@(FrameworkReference)"
                                       Condition="'%(FrameworkReference.IsTransitiveFrameworkReference)' != 'true'"/>
    </ItemGroup>
</Target>

How does that sound?

Read more comments on GitHub >

github_iconTop Results From Across the Web

dotnet restore solution is restoring projects like they are . ...
sln it is restoring the NuGet packages for just the .NET SDK style projects as expected. dotnet is installed with this GitHub action...
Read more >
Bring Your .NET Apps Forward with the .NET Upgrade ...
When NuGet packages are restored, the NuGet client automatically finds other packages needed by the project's direct dependencies and downloads them also. When ......
Read more >
MSBuild reference for .NET SDK projects
Reference for the MSBuild properties and items that are understood by the .NET SDK.
Read more >
Untitled
Asus k455la i3, Triska vs ingato, Nghien cuu khoa hoc benh tieu duong, Water warden sump pump! Tobf-5225? Motorcycle speedometer kph, Alumni sekar...
Read more >
Spock Framework Reference Documentation
The data provider holds all values for the variable, one per iteration. Any object that Groovy knows how to iterate over can be...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found