Skip to content

dotnet test fails: duplicate Microsoft.NETCore.App in ResolveFrameworkReferences #12254

Description

@jonathanpeppers

Summary

dotnet test fails for any .NET for Android test project starting with .NET SDK 11.0.100-preview.7.26376.106. The ResolveFrameworkReferences task crashes with a duplicate Microsoft.NETCore.App key.

This is an SDK-side bug, not a .NET for Android bug — see the "Not our bug" section below for proof. This issue exists to track re-enabling the test we had to disable.

Steps to Reproduce

  1. Install .NET SDK 11.0.100-preview.7.26376.106 (or newer) and the android workload.
  2. Attach an Android device or emulator.
  3. Run:
dotnet new androidtest -n ReproAndroidTest
cd ReproAndroidTest
dotnet build
dotnet test

You need a NuGet.config with the dotnet11 / dotnet11-transport dnceng public feeds to restore the preview Microsoft.NETCore.App.Runtime.android-* packs.

Expected Behavior

dotnet test deploys the app and runs the tests on the device.

Actual Behavior

dotnet test exits with code 1 and prints only a generic message:

Running the ComputeRunArguments target to discover run commands failed for this project. Fix the errors and warnings and run again.

The real error is visible only in a binlog:

Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(411,5): error MSB4018: The "ResolveFrameworkReferences" task failed unexpectedly.
System.ArgumentException: An item with the same key has already been added. Key: Microsoft.NETCore.App
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at System.Linq.Enumerable.SpanToDictionary[TSource,TKey](ReadOnlySpan`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at Microsoft.NET.Build.Tasks.ResolveFrameworkReferences.ExecuteCore()

Note that dotnet test writes two binlogs; the error only appears in the second one (*-dotnet-test.binlog).

Analysis

ResolveFrameworkReferences.ExecuteCore() does:

var resolvedRuntimePacks = ResolvedRuntimePacks.ToDictionary (rp => rp.GetMetadata (MetadataKeys.FrameworkName), StringComparer.OrdinalIgnoreCase);

This throws when @(ResolvedRuntimePack) contains two items whose FrameworkName is Microsoft.NETCore.App.

The .NET SDK now makes dotnet test device-aware. SolutionAndProjectUtility selects a device (running the ComputeAvailableDevices target) and then deploys and computes run arguments:

if (project.Targets.ContainsKey (Constants.DeployToDevice) &&
    !project.Build ([Constants.DeployToDevice], loggers)) {
    throw new GracefulException (CliCommandStrings.RunCommandDeployFailed);
}

if (!project.Build (s_computeRunArgumentsTarget, loggers)) {
    throw new GracefulException (CliCommandStrings.RunCommandEvaluationExceptionBuildFailed, s_computeRunArgumentsTarget [0]);
}

These are multiple ProjectInstance.Build () calls against the same ProjectInstance. The binlog shows ProcessFrameworkReferences executing twice, and because MSBuild task <Output ItemName="..." /> appends, the second execution adds a second Microsoft.NETCore.App runtime pack. ResolveFrameworkReferences then throws.

dotnet run does not hit this, which is what makes the failure look Android-specific when it is not.

Not our bug

Reproduced locally against a stock SDK and a released workload, with no .NET for Android PR content anywhere in the picture:

  • SDK 11.0.100-preview.7.26376.106 (side-loaded, official build)
  • Microsoft.Android.Sdk.Windows 37.0.0-preview.6.59 (released)
Command Result
dotnet test exit 1 — fails
dotnet test -p:RuntimeIdentifier=android-arm64 exit 1 — still fails
dotnet run exit 0 — deploys and runs on device

Two conclusions:

  1. Pinning a single RID does not help, so this is not caused by Android projects being multi-RID (android-arm64;android-x64). It is caused by the target running twice.
  2. dotnet run works on the identical project, confirming the problem is specific to the dotnet test code path.

There is no workaround available from the project or from our targets.

Impact on this repo

Xamarin.Android.Build.Tests.InstallAndRunTests.DotNetNewAndroidTest fails for the "test" cases. First seen in the dependency bump #12249, e.g. this build.

The "test" cases are disabled with Assert.Ignore referencing this issue. The "run" case still passes and remains enabled.

Action items

  • Fix in dotnet/sdk (either build a fresh ProjectInstance per Build () call, or issue a single Build () covering all required targets).
  • Once the fix flows into our SDK, remove the Assert.Ignore from DotNetNewAndroidTest and re-enable the "test" cases.
  • The now-redundant explicit dotnet build -t:Install step in that test can also be removed, since dotnet test runs DeployToDevice itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: App+Library BuildIssues when building Library projects or Application projects.needs-triageIssues that need to be assigned.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions