Description
Hello dotnet/arcade team,
I hope this message finds you well.
I've encountered a very persistent and challenging issue when trying to run XUnit tests on projects targeting .NET Framework 4.7.2 (and potentially other .NET Framework 4.x versions) in Visual Studio 2022. The error manifests as a System.IO.FileLoadException
with HRESULT 0x80131045
("Strong name signature verification failed") during the test discovery phase, specifically for the assembly Microsoft.DotNet.XUnitExtensions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
.
This problem makes testing for .NET Framework 4.7.2 extremely complex and unreliable. I believe providing unsigned versions of these problematic assemblies could greatly benefit developers in similar situations.
Problem Details:
- Assembly Involved:
Microsoft.DotNet.XUnitExtensions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
(and its dependencies, though the error consistently points to this specific assembly). - Context: Running XUnit tests (with
xUnit.net VSTest Adapter v2.8.2
) in Visual Studio 2022, which usestesthost.net472.exe
. The error also occurs when usingxunit.runner.console
directly. - Core Error Message:
System.IO.FileLoadException: Could not load file or assembly 'Microsoft.DotNet.XUnitExtensions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. Strong name signature verification failed. The assembly may have been tampered with, or it was delayed signed but not fully signed with the correct private key. (Exception from HRESULT: 0x80131045)
The stack trace indicates the error happens during test discovery, specifically when XUnit attempts reflection on methods (System.Reflection.CustomAttributeData.GetCustomAttributes
).
Troubleshooting Steps Performed (and their outcomes):
We invested significant time diagnosing and attempting to resolve this, exploring all standard and extreme workarounds:
- Bypassing Strong Name Verification (
sn -Vr
):
- Attempted both machine-wide (
sn -Vr *,*
) and assembly-specific (sn -Vr Microsoft.DotNet.XUnitExtensions.dll
). - Result: The error persisted. It appears the test runner's execution context in .NET Framework 4.x either ignores or overrides this directive due to security/isolation policies.
- Binding Redirects:
- Added
assemblyBinding
forMicrosoft.DotNet.XUnitExtensions
andSystem.Memory
(which caused a secondary issue) to the project'sApp.config
. - Also attempted to add
bindingRedirects
directly to thetesthost.net472.exe.config
file within the Visual Studio extensions directory. - Result: Did not resolve the
0x80131045
error forMicrosoft.DotNet.XUnitExtensions
.
- Fuslogvw (Assembly Binding Log Viewer):
- Used extensively to diagnose load failures.
- Result: Consistently showed failure for
Microsoft.DotNet.XUnitExtensions
withPublicKeyToken=31bf3856ad364e35
and HRESULT0x80131045
, even after attempts to modify the DLL in the project'sbin
directory. This strongly indicated a deeper CLR interaction issue.
- Manual Strong Name Removal (using
ildasm
/ilasm
):
- The Microsoft.DotNet.XUnitExtensions.dll assembly was decompiled to IL, its .publickey and .hash algorithm directives were removed, and the assembly was reassembled without a strong name.
- Verification:
sn.exe -Tp Microsoft.DotNet.XUnitExtensions.dll
confirmed the assembly was no longer strong-named. - Result (initial): The error persisted. This was particularly baffling, as an unsigned DLL should not trigger a strong name verification error.
- Crucial Discovery with Process Explorer and Final Resolution:
- By monitoring the
testhost.net472.exe
process with Process Explorer, we discovered that, contrary to expectations, DLLs were not being loaded from the project'sbin\Debug\net472
directory, but from a temporary directory (%USERPROFILE%\AppData\Local\Temp\xxxxxx\
) used for shadow copying. This revealed that the actual source of the loaded DLLs was the NuGet package cache. - Successful Workaround: We then repeated the strong name removal procedure (
ildasm
/ilasm
) directly on the copy ofMicrosoft.DotNet.XUnitExtensions.dll
located in the global NuGet package cache (%USERPROFILE%\.nuget\packages\microsoft.dotnet.xunitextensions\...\lib\net472\
). This was followed by a deep cleanup ofbin
/obj
folders, NuGet caches, and a full system reboot. - Result: The tests now run correctly.
Suspected Root Cause:
It appears the interaction between the strong name of Microsoft.DotNet.XUnitExtensions
(which might be a delayed-signed assembly that's not fully signed, or has signing peculiarities), the way the .NET Framework 4.x CLR handles strong name verification in test contexts (seemingly ignoring sn -Vr
), and the shadow copying mechanism (which copies strong-named versions from the NuGet cache), creates a problem that is incredibly difficult to work around without invasive manual file modifications.
Request / Proposal:
Given the significant complexity and the fragile nature of the workaround required (manual modification of DLLs in the NuGet cache is not sustainable for CI/CD or large-scale development), I kindly request that the dotnet/arcade
team consider providing alternative NuGet packages for .NET Framework (net4x) that contain unsigned versions of assemblies like Microsoft.DotNet.XUnitExtensions
.
This would allow developers facing these strong name verification issues to opt for an assembly version that does not trigger these conflicts with the .NET Framework CLR, greatly simplifying the testing and development process for those still relying on .NET Framework.
Thank you very much for your time and consideration of this issue.
Best regards,
Francesco Crimi