运行时创建C#Web API 2控制器时出现异常

运行时创建C#Web API 2控制器时出现异常,c#,reflection,controller,asp.net-web-api2,reflection.emit,C#,Reflection,Controller,Asp.net Web Api2,Reflection.emit,我想在启动时动态生成WebAPI2控制器。在本例中,我使用了反射 然而,当我编译它并启动服务时,当我通过HttpRequest调用它时出现异常。例外情况如下所示: { "Message": "An error has occurred.", "ExceptionMessage": "Unable to cast object of type 'System.Object[]' to type 'System.Web.Http.ParameterBindingAttribute[]

我想在启动时动态生成WebAPI2控制器。在本例中,我使用了反射

然而,当我编译它并启动服务时,当我通过HttpRequest调用它时出现异常。例外情况如下所示:

{
    "Message": "An error has occurred.",
    "ExceptionMessage": "Unable to cast object of type 'System.Object[]' to type 'System.Web.Http.ParameterBindingAttribute[]'.",
    "ExceptionType": "System.InvalidCastException",
    "StackTrace": " at System.Web.Http.Controllers.ReflectedHttpParameterDescriptor.GetCustomAttributes[TAttribute]() at System.Web.Http.Controllers.HttpParameterDescriptor.FindParameterBindingAttribute() at System.Web.Http.Controllers.HttpParameterDescriptor.get_ParameterBinderAttribute() at System.Web.Http.ModelBinding.DefaultActionValueBinder.GetParameterBinding(HttpParameterDescriptor parameter) at System.Array.ConvertAll[TInput,TOutput](TInput[] array, Converter`2 converter) at System.Web.Http.ModelBinding.DefaultActionValueBinder.GetBinding(HttpActionDescriptor actionDescriptor) at System.Web.Http.Controllers.HttpActionDescriptor.get_ActionBinding() at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem..ctor(HttpControllerDescriptor controllerDescriptor) at System.Web.Http.Controllers.ApiControllerActionSelector.GetInternalSelector(HttpControllerDescriptor controllerDescriptor) at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext) at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}


//ControllerBuilder.cs
//用于实现自定义控制器的生成器。问题似乎就在这里。也许我在这一部分配置错了?
公共静态类控制器生成器
{
公共静态ApicController CreateNewObject()
{
var ctrlType=CompileResultType(“TmpController”,新字典{{“tmpField”,“System.String”});
var ctrlObject=Activator.CreateInstance(ctrlType);
将ctrlObject返回为ApiController;
}
公共静态类型编译器结果类型(字符串类型签名,字典属性)
{
TypeBuilder tb=GetTypeBuilder(typeSignature);
tb.SetParent(typeof(ApiController));
ConstructorBuilder ctor=tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
foreach(propDic中的var项目)
{
CreateProperty(tb,item.Key,Type.GetType(item.Value));
}
//对于这个控制器,我只需要一个Get方法来处理Get请求
MethodBuilder myGetMethod=
tb.DefineMethod(“获取”,
方法属性。公共,
typeof(String),新类型[]{typeof(String)};
//为方法生成IL。
ILGenerator myMethodIL=myGetMethod.GetILGenerator();
myMethodIL.Emit(操作码.Ldarg_1);
myMethodIL.Emit(操作码.Ret);
类型objectType=tb.CreateType();
返回objectType;
}
私有静态类型生成器GetTypeBuilder(字符串类型签名)
{
var an=新程序集名称(类型签名);
AssemblyBuilder AssemblyBuilder=AppDomain.CurrentDomain.DefinedDynamicAssembly(an,AssemblyBuilderAccess.Run);
ModuleBuilder ModuleBuilder=assemblyBuilder.DefinedDynamicModule(“主模块”);
TypeBuilder tb=moduleBuilder.DefineType(类型签名,
TypeAttributes.Public|
TypeAttributes.Class|
TypeAttributes.AutoClass|
TypeAttributes.AnsiClass|
TypeAttributes.BeforeFieldInit|
TypeAttributes.AutoLayout,
无效);
返回结核病;
}
私有静态void CreateProperty(TypeBuilder tb、字符串propertyName、类型propertyType)
{
FieldBuilder FieldBuilder=tb.DefineField(“\u”+propertyName,propertyType,FieldAttributes.Private);
PropertyBuilder PropertyBuilder=tb.DefineProperty(propertyName,PropertyAttributes.HasDefault,propertyType,null);
MethodBuilder getPropMthdBldr=tb.DefineMethod(“get|”+propertyName,MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,propertyType,Type.EmptyTypes);
ILGenerator getIl=getPropMthdBldr.GetILGenerator();
getIl.Emit(操作码.Ldarg_0);
getIl.Emit(操作码.Ldfld,fieldBuilder);
getIl.Emit(操作码.Ret);
MethodBuilder setPropMthdBldr=
tb.DefineMethod(“设置”+属性名称,
MethodAttributes.Public|
MethodAttributes.SpecialName|
MethodAttributes.hidebysing,
空,新[]{propertyType});
ILGenerator setIl=setPropMthdBldr.GetILGenerator();
Label modifyProperty=setIl.DefineLabel();
Label exitSet=setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(操作码.Ldarg_0);
setIl.Emit(操作码Ldarg_1);
setIl.Emit(操作码.Stfld,fieldBuilder);
setIl.Emit(操作码Nop);
设置标记标签(exitSet);
setIl.Emit(操作码Ret);
SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}


我试图通过
ctrlType.GetMethod(“Get”).Invoke(ctrlObject,new[]{“param1”})调用CreateNewObject()中ctrlObject的“Get”方法。但是,我可以得到返回字符串“param1”!!!。那么,我可以知道是什么问题导致了我作为真正的Web API控制器请求时在顶部引用的异常吗?

我遇到了同样的问题,花了几个小时才弄清楚到底发生了什么

基本上,
ReflectedHttpParameterDescriptor.GetCustomAttributes[TaAttribute]()
试图从您正在创建的
get(string)
方法中获取参数信息,如参数名称和属性。问题在于
DefineMethod()
只声明参数类型,而不是
GetCustomAttributes()
需要的其他信息

解决方案是在定义方法后使用
MethodBuilder.DefineParameter()
提供此信息

//对于此控制器,我只需要一个Get方法来处理Get请求
MethodBuilder myGetMethod=tb.DefineMethod(
名称:“获取”,
属性:MethodAttributes.Public,
returnType:typeof(字符串),
parameterTypes:新类型[]{typeof(String)}
);
//定义参数
myGetMethod.DefineParameter(
位置:1,//0为返回值,1为第一个参数,2为第二个参数,依此类推。
属性:参数属性。无,
strParamName:“stringParam”
);

这已经花了我一天时间了。有人能帮我吗?提前谢谢。
// WebApiConfig.cs
// Register function in WebApiConfig

public static void Register(HttpConfiguration config)
{
    // Replace services by this line, to add my custom HttpControllerSelector
    config.Services.Replace(typeof(IHttpControllerSelector), new CustomHttpControllerSelector(config));

    // Web API routes
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}
// CustomeHttpControllerSelector.cs
// CustomHttpControllerSelector class to override the default one (In this case, the same controller will be returned for all request)

public class CustomHttpControllerSelector : DefaultHttpControllerSelector
{
    private readonly HttpConfiguration _configuration;

    public CustomHttpControllerSelector(HttpConfiguration configuration) : base(configuration)
    {
        _configuration = configuration;
    }

    public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
        var ctrl = ControllerBuilder.CreateNewObject();

        String controllerName = base.GetControllerName(request);
        return new HttpControllerDescriptor(_configuration, controllerName, ctrl.GetType());
    }
}
// ControllerBuilder.cs
// The builder to implement my custom controller. Seems the problem is here. Maybe I configured something wrong in this section?

public static class ControllerBuilder
{
    public static ApiController CreateNewObject()
    {
        var ctrlType = CompileResultType("TmpController", new Dictionary<string, string> { { "tmpField", "System.String" } });
        var ctrlObject = Activator.CreateInstance(ctrlType);

        return ctrlObject as ApiController;
    }

    public static Type CompileResultType(string typeSignature, Dictionary<string, string> propDic)
    {
        TypeBuilder tb = GetTypeBuilder(typeSignature);

        tb.SetParent(typeof(ApiController));

        ConstructorBuilder ctor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        foreach (var item in propDic)
        {
            CreateProperty(tb, item.Key, Type.GetType(item.Value));
        }

        // For this controller, I only want a Get method to server Get request
        MethodBuilder myGetMethod =
           tb.DefineMethod("Get",
              MethodAttributes.Public,
              typeof(String), new Type[] { typeof(String) });
        // Generate IL for method.
        ILGenerator myMethodIL = myGetMethod.GetILGenerator();
        myMethodIL.Emit(OpCodes.Ldarg_1);
        myMethodIL.Emit(OpCodes.Ret);

        Type objectType = tb.CreateType();
        return objectType;
    }

    private static TypeBuilder GetTypeBuilder(string typeSignature)
    {
        var an = new AssemblyName(typeSignature);
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
        TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
                TypeAttributes.Public |
                TypeAttributes.Class |
                TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass |
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.AutoLayout,
                null);
        return tb;
    }

    private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
    {
        FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
        PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
        MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
        ILGenerator getIl = getPropMthdBldr.GetILGenerator();

        getIl.Emit(OpCodes.Ldarg_0);
        getIl.Emit(OpCodes.Ldfld, fieldBuilder);
        getIl.Emit(OpCodes.Ret);

        MethodBuilder setPropMthdBldr =
            tb.DefineMethod("set_" + propertyName,
              MethodAttributes.Public |
              MethodAttributes.SpecialName |
              MethodAttributes.HideBySig,
              null, new[] { propertyType });

        ILGenerator setIl = setPropMthdBldr.GetILGenerator();
        Label modifyProperty = setIl.DefineLabel();
        Label exitSet = setIl.DefineLabel();

        setIl.MarkLabel(modifyProperty);
        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, fieldBuilder);

        setIl.Emit(OpCodes.Nop);
        setIl.MarkLabel(exitSet);
        setIl.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(getPropMthdBldr);
        propertyBuilder.SetSetMethod(setPropMthdBldr);
    }
}