runtime: Inconsistent behavior with Type.GetType compared to .NET Framework
Given the the following program:
using System;
namespace GetTypeRepro
{
class Program
{
static void Main(string[] args)
{
//Project is referencing Library.dll via PackageReference
//Uncomment this to see it work in netcoreapp3.0 (and netcoreapp2.2 if CopyLocalLockFileAssemblies is uncommented in the csproj)
//System.Reflection.Assembly.LoadFrom("GetTypeRepro.dll");
var type1 = Type.GetType("Library.Class1, Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", true); // < package version
var type2 = Type.GetType("Library.Class1, Library, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null", true); // == package version
var type3 = Type.GetType("Library.Class1, Library, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null", true); // > package version
}
}
}
There appears to be inconsistent behavior between the .NET Framework and .NET Core.
When run on net472
, all three Type.GetType
calls return the type from the referenced package.
However, when run on netcoreapp2.2
or netcoreapp3.0
, the first two return the type as expected, but the third call throws an exception instead:
System.IO.FileLoadException: Could not load file or assembly 'Library, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Library, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null'
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type, ObjectHandleOnStack keepalive)
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
at System.Type.GetType(String typeName, Boolean throwOnError)
at GetTypeRepro.Program.Main(String[] args) in C:\Code\GetTypeRepro\GetTypeRepro\Program.cs:line 18
One discovery I’ve made while investigating this is that the exception can be avoided if the referenced assembly is located next to the application assembly. This is the default in netcoreapp3.0
, and can be achieved on netcoreapp2.2
as well be setting CopyLocalLockFileAssemblies
to true
in the project file.
Once that is done, if you first call Assembly.LoadFrom
on the application assembly, then the third Type.GetType
stops throwing the exception and instead returns the type from the referenced assembly just like net472
does. This doesn’t prevent the exception if the assembly is still being referenced from the NuGet package cache, though.
I have a runnable repro available at https://github.com/bording/GetTypeRepro
This behavior seems very strange to me. Have I come across a bug, or is this somehow working as intended?
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 20 (20 by maintainers)
.NET Framework did not respect assembly versions some of the time. It was a bug in .NET Framework that is fixed in .NET Core.