不能调用控制器“控制器”操作方法“System.Web.Mvc.PartialViewResult富[T](T)”,因为操作方法是一个泛型方法 [英] Cannot call action method 'System.Web.Mvc.PartialViewResult Foo[T](T)' on controller 'Controller' because the action method is a generic method
问题描述
无法调用操作方法System.Web.Mvc.PartialViewResult脚上的控制器控制器,因为操作方法是一个泛型方法
<%Html.RenderAction(富,模型=模型}); %>
有没有办法来解决ASP MVC 2这个限制?我真的preFER使用一个通用的。我想出的解决办法是改变模型类型为对象。它的工作原理,但并不preferred:
公共PartialViewResult美孚< T>(T型),其中T:类
{
//做的东西
}
在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;
}
}
这篇关于不能调用控制器“控制器”操作方法“System.Web.Mvc.PartialViewResult富[T](T)”,因为操作方法是一个泛型方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!