System.Type.GetType does not throw when versions don't match

987 Views Asked by At

I one of my xUnit tests, I was using following code to locate a matching type:

var type = System.Type.GetType (typeName, throwOnError: false);

where typeName looks like:

Epsitec.Lydia.EventStore.TestBinaryEventStore+SimpleEvent, Tests.Lydia.Framework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=361fc18aa5d4142d

If the type did not match exactly (e.g. because the Version part of the fully qualified type name diverged), I used to get a System.IO.FileLoadException with previous versions of .NET 4.5.x. Since I got my latest Windows Update delivered, which coincidentally contains .NET 4.5.2, I no longer get an exception if I do not specify the exact same version.

I initially thought this was caused by a new behaviour of GetType in .NET 4.5.2, but this seems not to be the case. I did not find any information about this change in MSDN's documentation.

I tried replicating this behaviour in a project outside of an xUnit test, but then I get the expected behaviour (System.IO.FileLoadException gets thrown because the type does not match).

What am I missing here? Any idea as to how I should proceed with my investivations?

Additional information

I used Fuslogvw to investigate further. The type resolution does indeed fail as this trace shows:

*** Assembly Binder Log Entry  (01.04.2015 @ 09:11:19) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 12.0\COMMON7\IDE\EXTENSIONS\O3TVLY23.2NC\PlugIns\CR_ExtUnitTestRunnerNet4.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Tests.Lydia.Framework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4681e18aa5df9116
 (Fully-specified)
LOG: Appbase = file:///C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO 12.0/COMMON7/IDE/EXTENSIONS/O3TVLY23.2NC/PlugIns
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = C:\Users\Arnaud\AppData\Local\Temp\85454750-eabd-4a3b-a5f2-91f3b104eba4
LOG: AppName = 85454750-eabd-4a3b-a5f2-91f3b104eba4
Calling assembly : Tests.Lydia.Framework, Version=1.1.1514.0, Culture=neutral, PublicKeyToken=4681e18aa5df9116.
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: S:\git\rnd\lydia\Tests.Lydia.Framework\bin\Release\Tests.Lydia.Framework.dll.config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Tests.Lydia.Framework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4681e18aa5df9116
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO 12.0/COMMON7/IDE/EXTENSIONS/O3TVLY23.2NC/PlugIns/Tests.Lydia.Framework.DLL.
LOG: Attempting download of new URL file:///C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO 12.0/COMMON7/IDE/EXTENSIONS/O3TVLY23.2NC/PlugIns/Tests.Lydia.Framework/Tests.Lydia.Framework.DLL.
LOG: Attempting download of new URL file:///C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO 12.0/COMMON7/IDE/EXTENSIONS/O3TVLY23.2NC/PlugIns/Tests.Lydia.Framework.EXE.
LOG: Attempting download of new URL file:///C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO 12.0/COMMON7/IDE/EXTENSIONS/O3TVLY23.2NC/PlugIns/Tests.Lydia.Framework/Tests.Lydia.Framework.EXE.
LOG: Attempting download of new URL file:///S:/git/rnd/lydia/Tests.Lydia.Framework/bin/Release/Tests.Lydia.Framework.DLL.
LOG: Assembly download was successful. Attempting setup of file: S:\git\rnd\lydia\Tests.Lydia.Framework\bin\Release\Tests.Lydia.Framework.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Tests.Lydia.Framework, Version=1.1.1514.0, Culture=neutral, PublicKeyToken=4681e18aa5df9116
WRN: Comparing the assembly name resulted in the mismatch: Minor Version
ERR: The assembly reference did not match the assembly definition found.
ERR: Run-from-source setup phase failed with hr = 0x80131040.
LOG: Attempting download of new URL file:///S:/git/rnd/lydia/Tests.Lydia.Framework/bin/Release/Tests.Lydia.Framework/Tests.Lydia.Framework.DLL.
LOG: Attempting download of new URL file:///S:/git/rnd/lydia/Tests.Lydia.Framework/bin/Release/Tests.Lydia.Framework.EXE.
LOG: Attempting download of new URL file:///S:/git/rnd/lydia/Tests.Lydia.Framework/bin/Release/Tests.Lydia.Framework/Tests.Lydia.Framework.EXE.
LOG: All probing URLs attempted and failed.

Still more context

I am running the code from within an xUnit test which is also referencing multiple other libraries. Trying to duplicate this outside of the original solution still does not exhibit the issue.

How could a referenced assembly tweak GetType in such a way that it would suddenly ignore the version part of the assembly qualified type name?

2

There are 2 best solutions below

5
Guillaume On

xUnit have code registering to AppDomain.AssemblyResolve event and ignoring version and signature :

    Assembly LoadAssembly(AssemblyName assemblyName)
    {
        var path = Path.Combine(folder, assemblyName.Name);
        return LoadAssembly(path + ".dll") ?? LoadAssembly(path + ".exe");
    }

https://github.com/xunit/xunit/blob/master/src/common/AssemblyHelper.cs

If your runner is using it that's probably why you have this issue only in unit tests.

0
Pierre Arnaud On

The issue is not related to xUnit or any of the other assemblies referenced by my project. I've been able to replicate the same behaviour in a minimalist project and the source of this strange behaviour seems to originate from the CodeRush (14.2.6.0) tool I use to interact with my tests.

I've opened an issue with DevExpress and I will update this answer when I get a reply from their support team.