'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 |
|---|
