不能调用控制器“控制器”操作方法“System.Web.Mvc.PartialViewResult富[T](T)”,因为操作方法是一个泛型方法控制器、操作方法、是一个、方法

2023-09-03 05:21:39 作者:策马西风

无法调用操作方法System.Web.Mvc.PartialViewResult脚上的控制器控制器,因为操作方法是一个泛型方法

 <%Html.RenderAction(富,模型=模型}); %>
 

有没有办法来解决ASP MVC 2这个限制?我真的preFER使用一个通用的。我想出的解决办法是改变模型类型为对象。它的工作原理,但并不preferred:

 公共PartialViewResult美孚< T>(T型),其中T:类
    {
      //做的东西
    }
 
SSM mysql24小时宿舍管理员系统 计算机毕业设计源码41854

解决方案

在code抛出这是默认ActionDescriptor里面:

 内部静态字符串VerifyActionMethodIsCallable(MethodInfo的MethodInfo的){
        //我们不能调用实例方法,其中这个参数是一种比ControllerBase其他
        如果(methodInfo.IsStatic&安培;!&安培;!typeof运算(ControllerBase).IsAssignableFrom(methodInfo.ReflectedType)){
            返回的String.Format(CultureInfo.CurrentUICulture,MvcResources.ReflectedActionDescriptor_CannotCallInstanceMethodOnNonControllerType,
                MethodInfo的,methodInfo.ReflectedType.FullName);
        }

        //我们不能调用开放泛型类型参数的方法
        如果(methodInfo.ContainsGenericParameters){
            返回的String.Format(CultureInfo.CurrentUICulture,MvcResources.ReflectedActionDescriptor_CannotCallOpenGenericMethods,
                MethodInfo的,methodInfo.ReflectedType.FullName);
        }

        //我们不能调用与REF /输出参数的方法
        信息参数[] parameterInfos = methodInfo.GetParameters();
        的foreach(信息参数信息参数在parameterInfos){
            如果(parameterInfo.IsOut || parameterInfo.ParameterType.IsByRef){
                返回的String.Format(CultureInfo.CurrentUICulture,MvcResources.ReflectedActionDescriptor_CannotCallMethodsWithOutOrRefParameters,
                    MethodInfo的,methodInfo.ReflectedType.FullName,信息参数);
            }
        }

        //我们可以调用此方法
        返回null;
    }
 

由于code呼吁methodInfo.ContainsGenericParameters我不认为有一种方法来覆盖此行为不会创建自己的ActionDescriptor。从扫了一眼源$ C ​​$ C这似乎是不平凡的。

另一种方法是使你的控制器类通用的,创建一个自定义的通用控制器工厂。我有一些实验code,创建一个通用控制器。它的哈克,但它只是一个个人的实验。

 公共类GenericControllerFactory:DefaultControllerFactory
{
    保护覆盖类型GetControllerType(System.Web.Routing.RequestContext的RequestContext,串controllerName)
    {
        //泛型类型参数不要紧这里
        如果(controllerName.EndsWith(CO))//假设我们没有任何其它通用控制器这里
            返回的typeof(GenericController&其中;&GT);

        返回base.GetControllerType(RequestContext的,controllerName);

        抛出新的InvalidOperationException异常(通用工厂是不是能解决控制器类型);
    }

    保护覆盖IController GetControllerInstance(System.Web.Routing.RequestContext的RequestContext,类型controllerType)
    {
        //是我们要求的通用控制器?
        如果(requestContext.RouteData.Values​​.ContainsKey(modelType))
        {
            。字符串的typeName = requestContext.RouteData.Values​​ [modelType]的ToString();
            //施法时间
            返回GetGenericControllerInstance(typeName的,RequestContext的);
        }

        如果(!typeof运算(IController).IsAssignableFrom(controllerType))
            抛出新的ArgumentException(的String.Format(请求的类型不是控制器:{0},controllerType.Name),controllerType);

        返回base.GetControllerInstance(RequestContext的,controllerType);
    }

    ///<总结>
    ///返回一个通用IController绑请求的类型名称。
    ///因为我们只有一个单一的通用控制器的类型是很难codeD现在
    ///< /总结>
    ///< PARAM NAME =typeName的>< /参数>
    ///<返回>< /回报>
    私人IController GetGenericControllerInstance(字符串typeName的,RequestContext中的RequestContext)
    {
        VAR actionName = requestContext.RouteData.Values​​ [行动];

        //尝试解决一个自定义视图模型

        键入actionModelType = Type.GetType(Brainnom.Web.Models。+ +的typeName + actionName视图模型,Brainnom.Web,假的,真正的)?
            Type.GetType(Brainnom.Web.Models。+ +的typeName,Brainnom.Web,假的,真正的);

        键入controllerType = typeof运算(GenericController<>)MakeGenericType(actionModelType)。

        VAR controllerBase = Activator.CreateInstance(controllerType,新的对象[0]​​ {})为IController;

        返回controllerBase;
    }
}
 

Cannot call action method 'System.Web.Mvc.PartialViewResult FooT' on controller 'Controller' because the action method is a generic method

<% Html.RenderAction("Foo", model = Model}); %>

Is there a workaround for this limitation on ASP MVC 2? I would really prefer to use a generic. The workaround that I have come up with is to change the model type to be an object. It works, but is not preferred:

    public PartialViewResult Foo<T>(T model) where T : class
    {
      // do stuff
    }

解决方案

The code that throws that is inside the default ActionDescriptor:

    internal static string VerifyActionMethodIsCallable(MethodInfo methodInfo) {
        // we can't call instance methods where the 'this' parameter is a type other than ControllerBase
        if (!methodInfo.IsStatic && !typeof(ControllerBase).IsAssignableFrom(methodInfo.ReflectedType)) {
            return String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_CannotCallInstanceMethodOnNonControllerType,
                methodInfo, methodInfo.ReflectedType.FullName);
        }

        // we can't call methods with open generic type parameters
        if (methodInfo.ContainsGenericParameters) {
            return String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_CannotCallOpenGenericMethods,
                methodInfo, methodInfo.ReflectedType.FullName);
        }

        // we can't call methods with ref/out parameters
        ParameterInfo[] parameterInfos = methodInfo.GetParameters();
        foreach (ParameterInfo parameterInfo in parameterInfos) {
            if (parameterInfo.IsOut || parameterInfo.ParameterType.IsByRef) {
                return String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_CannotCallMethodsWithOutOrRefParameters,
                    methodInfo, methodInfo.ReflectedType.FullName, parameterInfo);
            }
        }

        // we can call this method
        return null;
    }

Because the code is calling "methodInfo.ContainsGenericParameters" I don't think there is a way to override this behavior without creating your own ActionDescriptor. From glancing at the source code this seems non-trivial.

Another option is to make your controller class generic and create a custom generic controller factory. I have some experimental code that creates a generic controller. Its hacky but its just a personal experiment.

public class GenericControllerFactory : DefaultControllerFactory
{
    protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        //the generic type parameter doesn't matter here
        if (controllerName.EndsWith("Co"))//assuming we don't have any other generic controllers here
            return typeof(GenericController<>);

        return base.GetControllerType(requestContext, controllerName);

        throw new InvalidOperationException("Generic Factory wasn't able to resolve the controller type");
    }

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        //are we asking for the generic controller?
        if (requestContext.RouteData.Values.ContainsKey("modelType"))
        {
            string typeName = requestContext.RouteData.Values["modelType"].ToString();
            //magic time
            return GetGenericControllerInstance(typeName, requestContext);
        }

        if (!typeof(IController).IsAssignableFrom(controllerType))
            throw new ArgumentException(string.Format("Type requested is not a controller: {0}",controllerType.Name),"controllerType");

        return base.GetControllerInstance(requestContext, controllerType);
    } 

    /// <summary>
    /// Returns the a generic IController tied to the typeName requested.  
    /// Since we only have a single generic controller the type is hardcoded for now
    /// </summary>
    /// <param name="typeName"></param>
    /// <returns></returns>
    private IController GetGenericControllerInstance(string typeName, RequestContext requestContext)
    {
        var actionName = requestContext.RouteData.Values["action"];

        //try and resolve a custom view model

        Type actionModelType = Type.GetType("Brainnom.Web.Models." + typeName + actionName + "ViewModel, Brainnom.Web", false, true) ?? 
            Type.GetType("Brainnom.Web.Models." + typeName + ",Brainnom.Web", false, true);

        Type controllerType = typeof(GenericController<>).MakeGenericType(actionModelType);

        var controllerBase = Activator.CreateInstance(controllerType, new object[0] {}) as IController;

        return controllerBase;
    }
}