Describe the bug
We were upgrading our project from .net 8 to .net 10 and ran into the problem described in https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/KnownIssues.md#failed-to-resolve-assembly-during-instrumentation.
In our case the issue was: An optional parameter whose default value is a constant defined in a shared-framework assembly makes coverlet drop the entire containing module from coverage. Tests still pass and a coverage file is still written — it just silently omits the assembly. We noticed this when our pr gate, which validates coverage levels, failed after the upgrade.
I think this conclusion is no longer correct, and rather than spamming you with a patch, would like your approval of this issue first.
Both suggestions in the exception message and in KnownIssues.md were tested on SDK 10.0.401:
CopyLocalLockFileAssemblies=true — no effect. Framework provision wins regardless. (KnownIssues.md already anticipates this for the shared framework.)
PreserveCompilationContext=true — populates refs/ with the assembly, but Cecil does not search refs/, so instrumentation still fails.
That leaves the manual-copy workaround from #560.
Why did this suddenly appear when we upgraded the framework? Whether the assembly is copied to the output folder depends on SDK conflict resolution comparing file versions between the package and the targeting pack's PlatformManifest.txt. Same source, same package version, two SDK feature bands:
| SDK |
targeting pack manifest file version |
package file version |
Microsoft.Extensions.* copied |
result |
| 10.0.204 |
10.0.8 — 10.0.826.23019 |
10.0.11 — 10.0.1126.37416 |
6 assemblies |
Lib present, line-rate="1" |
| 10.0.401 |
10.0.12 — 10.0.1226.42308 |
10.0.11 — 10.0.1126.37416 |
none |
empty report |
Bumping the package to match does not help: ties go to the platform (verified with 10.0.12 against pack 10.0.12).
To Reproduce
Two projects. Lib takes a transitive FrameworkReference to Microsoft.AspNetCore.App via OpenTelemetry.Instrumentation.AspNetCore, and exposes a method whose optional parameter defaults to an enum constant from Microsoft.Extensions.Logging.Abstractions.
Lib/Lib.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.11" />
<!-- Brings a transitive FrameworkReference to Microsoft.AspNetCore.App. -->
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
</ItemGroup>
</Project>
Lib/Thing.cs
using Microsoft.Extensions.Logging;
namespace Lib;
public static class Thing
{
public static int Go(LogLevel level = LogLevel.Error)
{
return level == LogLevel.Error ? 1 : 0;
}
}
Tests/Tests.csproj — net10.0, ProjectReference to Lib, plus Microsoft.NET.Test.Sdk 18.0.1, xunit 2.9.2, xunit.runner.visualstudio 2.8.2, coverlet.collector 6.0.4. One [Fact] calling Lib.Thing.Go().
dotnet test Tests\Tests.csproj --collect "XPlat Code Coverage"
Expected behavior
Coverage file written with data.
Actual behavior
The test passes. coverage.cobertura.xml is written and contains no packages at all. The data-collector diagnostic log shows:
[coverlet]Unable to instrument module: ...\Tests\bin\Debug\net10.0\Lib.dll
Coverlet.Core.Exceptions.CecilAssemblyResolutionException: AssemblyResolutionException for
'Microsoft.Extensions.Logging.Abstractions, Version=10.0.0.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60'
---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly
at Coverlet.Core.Instrumentation.NetstandardAwareAssemblyResolver.TryWithCustomResolverOnDotNetCore
at Mono.Cecil.MetadataBuilder.GetConstantType(TypeReference constant_type, Object constant)
at Mono.Cecil.MetadataBuilder.AddConstant(IConstantProvider owner, TypeReference type)
at Mono.Cecil.MetadataBuilder.AddParameter(...)
Removing = LogLevel.Error from the signature makes the assembly instrument normally. The Cecil stack is narrow: the assembly is needed only to compute the underlying type of the enum constant used as the default value.
Configuration (please complete the following information):
.net 10.0.401
coverlet 6.0.4
Describe the bug
We were upgrading our project from .net 8 to .net 10 and ran into the problem described in https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/KnownIssues.md#failed-to-resolve-assembly-during-instrumentation.
In our case the issue was: An optional parameter whose default value is a constant defined in a shared-framework assembly makes coverlet drop the entire containing module from coverage. Tests still pass and a coverage file is still written — it just silently omits the assembly. We noticed this when our pr gate, which validates coverage levels, failed after the upgrade.
I think this conclusion is no longer correct, and rather than spamming you with a patch, would like your approval of this issue first.
Both suggestions in the exception message and in
KnownIssues.mdwere tested on SDK 10.0.401:CopyLocalLockFileAssemblies=true— no effect. Framework provision wins regardless. (KnownIssues.mdalready anticipates this for the shared framework.)PreserveCompilationContext=true— populatesrefs/with the assembly, but Cecil does not searchrefs/, so instrumentation still fails.That leaves the manual-copy workaround from #560.
Why did this suddenly appear when we upgraded the framework? Whether the assembly is copied to the output folder depends on SDK conflict resolution comparing file versions between the package and the targeting pack's
PlatformManifest.txt. Same source, same package version, two SDK feature bands:Microsoft.Extensions.*copied10.0.826.2301910.0.1126.37416Libpresent,line-rate="1"10.0.1226.4230810.0.1126.37416Bumping the package to match does not help: ties go to the platform (verified with 10.0.12 against pack 10.0.12).
To Reproduce
Two projects.
Libtakes a transitiveFrameworkReferencetoMicrosoft.AspNetCore.AppviaOpenTelemetry.Instrumentation.AspNetCore, and exposes a method whose optional parameter defaults to an enum constant fromMicrosoft.Extensions.Logging.Abstractions.Lib/Lib.csprojLib/Thing.csTests/Tests.csproj—net10.0,ProjectReferencetoLib, plusMicrosoft.NET.Test.Sdk18.0.1,xunit2.9.2,xunit.runner.visualstudio2.8.2,coverlet.collector6.0.4. One[Fact]callingLib.Thing.Go().Expected behavior
Coverage file written with data.
Actual behavior
The test passes.
coverage.cobertura.xmlis written and contains no packages at all. The data-collector diagnostic log shows:Removing
= LogLevel.Errorfrom the signature makes the assembly instrument normally. The Cecil stack is narrow: the assembly is needed only to compute the underlying type of the enum constant used as the default value.Configuration (please complete the following information):
.net 10.0.401
coverlet 6.0.4