Description
Description
From the assembly loaded into Custom AssemblyLoadContext we are calling TypeDescriptor.GetConverter(Type)
method. This method is defined in System.ComponentModel.TypeConverter.dll
that is part of .NET 6 runtime, so it’s loaded into AssemblyLoadContext.Default.
Inside of the the TypeDescriptor.GetConverter(Type)
there is a call to Type.GetType(string)
for the type from the assembly that is loaded in Custom AssemblyLoadContext. So, unfortunately, it fails to get this type.
Calling Type.GetType(string)
without TypeDescriptor.GetConverter(Type)
in the same place from the assembly loaded in from the Custom AssemblyLoadContext returns type properly.
Reproduction Steps
To simplify repro I'll also add link to zip file with the sample solution.
Below is the description of the process to create this solution:
You need two projects to reproduce the issue. The first one will create an assembly (the TestAssembly
) and the second one will run it in the Custom AssemblyLoadContext (the AssemblyLoadContextRepro
).
TestAssembly
code:
using System;
using System.ComponentModel;
namespace TestAssembly
{
public class Test
{
public static void Run()
{
// Returns type from the Current AssemblyLoadContext properly.
var type = Type.GetType("TestAssembly.MyClassConverter, TestAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
// Tries to get type from AssemblyLoadContext.Default and fails because of it.
var fromConverter = TypeDescriptor.GetConverter(typeof(MyClass));
}
}
[TypeConverter(typeof(MyClassConverter))]
public class MyClass { }
public class MyClassConverter : TypeConverter { }
}
AssemblyLoadContextRepro
that would load assembly:
using System.Runtime.Loader;
using System.Reflection;
using System;
using System.IO;
namespace AssemblyLoadContextRepro
{
internal class Program
{
static void Main(string[] args)
{
var context = new TestAssemblyLoadContext();
var assembly = context.LoadFromAssemblyName(new AssemblyName("TestAssembly"));
var type = assembly.GetType("TestAssembly.Test");
var method = type.GetMethod("Run");
method.Invoke(null, Array.Empty<object>());
}
}
internal class TestAssemblyLoadContext : AssemblyLoadContext
{
private string assembliesLocation;
public TestAssemblyLoadContext() : base("Custom")
{
// path to binaries of TestAssembly project.
assembliesLocation = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\TestAssembly\bin\Debug\net6.0\");
}
protected override Assembly Load(AssemblyName assemblyName)
{
var path = Path.Combine(assembliesLocation, assemblyName.Name + ".dll");
if (File.Exists(path))
{
var assembly = this.LoadFromAssemblyPath(path);
return assembly;
}
return null;
}
}
}
Expected behavior
I would prefer TypeDescriptor.GetConverter(Type)
to behave in the same way as Type.GetType(string)
and use AssemblyLoadContext
of the code that calling it if possible. Because System.ComponentModel.TypeConverter.dll
is distributed with .NET runtime and would be always loaded in AssemblyLoadContext.Default
that makes it unusable for custom contexts.
Actual behavior
TypeDescriptor.GetConverter(Type)
always use AssemblyLoadContext.Default
and as a result unable to load converters from assemblies in Custom AssemblyLoadContext.
Regression?
No response
Known Workarounds
Wrapping call to into EnterContextualReflection
allows it to work correctly:
using (AssemblyLoadContext.EnterContextualReflection(Assembly.GetExecutingAssembly()))
{
TypeDescriptor.GetConverter(type);
}
Not working workarounds:
- Loading assemblies into AssemblyLoadContext.Default defeats the purpose of having separate contexts.
- Loading
System.ComponentModel.TypeConverter.dll
into Custom AssemblyLoadContext allowsType.GetType(string)
to get converter type, but we end up with the same assembly loaded into both contexts that make it unusable, for example, resulted type could not be assigned toITypeConverter
, becausetypeof(ITypeConverter)
returns type from theSystem.ComponentModel.TypeConverter.dll
inAssemblyLoadContext.Default
. SoTypeDescriptor.GetConverter(Type)
fails to return converter in this case also.
Configuration
No response
Other information
No response