'C#: How to call base function in dynamic type's defined method

I create a dynamic DLL, and Class Type which is a derived class of Foo, named "FooProxy". I want to define a method on "FooProxy" called "DoSomethingProxy". "DoSomethingProxy" calls base.DoSomething() and return what it returns. I wrote a demo like below, but I get "Common Language Runtime detected an invalid program." when trying to call base.DoSomething(). How Should I use Emit call to avoid this error? Any advice would be appreciated. Blow Example is OK to run.

using System.Reflection;
using System.Reflection.Emit;
using Microsoft.AspNetCore.Mvc;

namespace DynamicAddController;

public class Program
{
    static void Main(string[] args)
    {
        WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

        Type type = Type.GetType("DynamicAddController.Foo");
        AssemblyName aName = new System.Reflection.AssemblyName("SomeNamespace");
        AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
        ModuleBuilder mb = ab.DefineDynamicModule(aName.Name + ".dll");
        TypeBuilder tb = mb.DefineType(type.Name + "Proxy", TypeAttributes.Public, type);

        var ctorParams = new Type[] { typeof(string) };
        ConstructorInfo attrCtorInfo = typeof(ApiControllerAttribute).GetConstructors()[0];
        CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { });
        tb.SetCustomAttribute(attrBuilder);
        var methodName = "DoSomething";

        // 设route
        var classCtorInfo1 = typeof(HttpGetAttribute).GetConstructor(ctorParams);
        CustomAttributeBuilder myCaBuilder3 = new CustomAttributeBuilder(
            classCtorInfo1,
            new object[] { methodName });
        tb.SetCustomAttribute(myCaBuilder3);
        // Now, let's build a method and add a custom attribute to it.
        var mi = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance);
        var x = mi.ReturnType;
        MethodBuilder myMethodBuilder = tb.DefineMethod(methodName + "Proxy",
            MethodAttributes.Public, x,
            new Type[] { });

        var classCtorInfo = typeof(HttpGetAttribute).GetConstructor(ctorParams);
        CustomAttributeBuilder myCaBuilder2 = new CustomAttributeBuilder(
            classCtorInfo,
            new object[] { methodName });

        myMethodBuilder.SetCustomAttribute(myCaBuilder2);
        ILGenerator myIL = myMethodBuilder.GetILGenerator();
        var argTypes = mi.GetGenericArguments();
        myIL.Emit(OpCodes.Nop);
        myIL.Emit(OpCodes.Call, mi); // If I comment this line, I won't get exception, but I cannot get the result of foo.DoSomething.
        myIL.Emit(OpCodes.Ldstr, "are many bananas");
        myIL.Emit(OpCodes.Ret);


        Type? myType = tb.CreateType();

        object myInstance = Activator.CreateInstance(myType);

        object[] customAttrs = myType.GetCustomAttributes(true);

        Console.WriteLine("Custom Attributes for Type 'MyType':");

        object attrVal = null;

        foreach (object customAttr in customAttrs)
        {
            //attrVal = typeof(ApiControllerAttribute).InvokeMember("Creator", BindingFlags.GetProperty, null, customAttr, new object[] { });
            Console.WriteLine("-- Attribute: [{0} = \"{1}\"]", customAttr, attrVal);
        }

        Console.WriteLine("Custom Attributes for Method 'HelloWorld()' in 'MyType':");

        customAttrs = myType.GetMember(methodName + "Proxy")[0].GetCustomAttributes(true);

        foreach (object customAttr in customAttrs)
        {
            attrVal = typeof(HttpGetAttribute).InvokeMember("Template",
                BindingFlags.GetProperty,
                null, customAttr, new object[] { });
            Console.WriteLine("-- Attribute: [{0} = \"{1}\"]", customAttr, attrVal);
        }

        Console.WriteLine("---");

        Console.WriteLine(myType.InvokeMember(methodName + "Proxy",
            BindingFlags.InvokeMethod,
            null, myInstance, new object[] { }));

        // Add services to the container.
        builder.Services.AddRazorPages();
        builder.Services.AddControllers().AddApplicationPart(myInstance.GetType().Assembly);
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        var app = builder.Build();

        // Configure the HTTP request pipeline.
        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseSwagger();
        app.UseSwaggerUI();
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();
        //Assert.IsNotNull(attr);
        //Assert.AreEqual(attr.Value, "Some Value");
        //var r = exported.First(x=>x.)
        app.MapRazorPages();
        app.MapControllers();

        app.Run();

    }
}

public class Foo // Not Impl ControllerBase
{
    public string DoSomething()
    {
        return "I' am Foo, I can wash your dishes, but I am not a controller.";
    }
}

Here is the csproj file setting:


    <Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="Controllers\" />
    <Folder Include="demo\" />

    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>

</Project>



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source