Reflection: Create instance of a class that inherit from another class located in separate assembly

I created an empty web form application that run under .Net Framework 4.7.2 and created a webform and a class named MyClass:

namespace WebApplication1
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        public string GetText()
        {
            return "Message of Web Form 1";
        }
    }
}

and:

namespace WebApplication1
{
    public class MyClass
    {
        public string GetText()
        {
           return "Message from MyClass";
        }
    }
}

and I publish it using "Merge all assemblies in one assembly" option:

enter image description here

Then I want to get type and then create instance of WebForm1 and MyClass.

I wrote this code in a console application that run under .Net 5:

Assembly asm = Assembly.LoadFrom(@"C:\Pub\bin\WebApplication1.dll");

Type tMyClass = asm.GetType("WebApplication1.MyClass");
Type t = asm.GetType("WebApplication1.WebForm1"); <----Error

After the code has run, tMyClass has the correct type:

enter image description here]

but when I try to get the type of WebForm1, I get an error:

enter image description here

System.TypeLoadException: 'Could not load type 'System.Web.UI.Page' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.'

How can I get type of WebForm1 and create an instance of it?


Solution 1:

The reason for the error is because System.Web.UI.Page does not exist in .NET 5. So you can't load the assembly for the purpose of executing the code within your console app.

However, you can still load the metadata of your class WebApplication1.WebForm1 in a reflection-only context for the purpose of examining the type. The way you do it in .NET 5 is different than .NET Framework by using a MetadataLoadContext from this NuGet package.

var dllPath = @"C:\Pub\bin\WebApplication1.dll";

var paths = new List<string>();
paths.AddRange(Directory.GetFiles(Path.GetDirectoryName(dllPath), "*.dll"));
paths.AddRange(Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll"));

using var context = new MetadataLoadContext(new PathAssemblyResolver(paths));
var asm = context.LoadFromAssemblyPath(dllPath);
var yourType = asm.GetType("WebApplication1.WebForm1");

Also note, if you're trying to access the methods that are defined in a not loaded assembly, you will still get error:

yourType.GetMethods(); // Error
yourType.GetMethods(BindingFlags.DeclaredOnly); // OK

Solution 2:

You load an assembly built in .NET Framework via reflection on .NET Core, but some of the classes in System.Web namespace are not supported in .NET Core. It load user code parts. And other parts may not work. In your case the requested class of the code compiled for .NET Framework is not part of .NET Core. System.Web is for Asp.Net and in .NET Core the System.Web namespace exists and could technically be called but it won't work like you want.