Я генерирую контроллеры Web API во время выполнения (. Net Core 3.0). У меня есть базовый контроллер c, от которого я наследую сгенерированный контроллер, и при настройке действий http я хочу вызвать метод из базового класса и вернуть его значение. Когда я вызываю / api / Foo / 1, возникает InvalidProgramException.
EDIT : я упростил код и добавил работающий пример (см. Рабочий пример проекта ) .
Чего я хочу добиться:
public class FooController : GenericBaseController<Foo, int> {
[HttpGet]
public Foo Get(int id){
return base.DoGet(id);
}
}
Как выглядит базовый контроллер:
[Route("api/[controller]")]
[ApiController]
public abstract class GenericBaseController<T, TId> : ControllerBase {
protected T DoGet(TId id)
{
return default;
}
}
Как выглядит код компоновщика типов, устанавливающий метод:
MethodBuilder builder = tb.DefineMethod("Get", MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Final, modelType, new Type[] {typeof(int)});
builder.DefineParameter(1, ParameterAttributes.None, "id");
ConstructorInfo httpCtorInfo = typeof(HttpGetAttribute).GetConstructors().First();
CustomAttributeBuilder httpAttrBuilder = new CustomAttributeBuilder(httpCtorInfo, new object[0]);
builder.SetCustomAttribute(httpAttrBuilder);
ILGenerator emitter = builder.GetILGenerator();
emitter.Emit(OpCodes.Nop);
emitter.Emit(OpCodes.Ldarg_0);
emitter.Emit(OpCodes.Ldarg_1);
MethodInfo baseMethod = baseCrudController.GetMethod("DoGet", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
emitter.Emit(OpCodes.Call, baseMethod);
emitter.Emit(OpCodes.Stloc_0);
emitter.Emit(OpCodes.Br_S, 0011);
emitter.Emit(OpCodes.Ldloc_0);
emitter.Emit(OpCodes.Ret);
Я попытался восстановить из того, что я получил, когда я использую коды операций, используя читатель, найденный здесь https://www.codeproject.com/Articles/14058/Parsing-the-IL-of-a-Method-Body
0000 : nop
0001 : ldarg.0
0002 : ldarg.1
0003 : call instance FooProject.Controllers.GenericBaseController`1[System.Int32]::DoGet()
0008 : stloc.0
0009 : br.s 0011
0011 : ldloc.0
0012 : ret