27

我正在尝试创建一个通用控制器,即:

public class MyController<T> : Controller where T : SomeType
{ ... }

但是,当我尝试使用它时,我到处都遇到这个错误......

控制器名称必须以“Controller”结尾

所以,我的问题是,是否可以在 asp.net mvc 中制作通用控制器?

谢谢!

4

5 回答 5

38

如果我正确理解您,您正在尝试做的是通过 T 类型的通用控制器路由给定模型的所有请求。

您希望 T 根据请求的型号而有所不同。

你想/Product/Index触发MyController<Product>.Index()

这可以通过编写自己IControllerFactory的方法并实现如下CreateController方法来完成:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    Type controllerType = Type.GetType("MyController")
                              .MakeGenericType(Type.GetType(controllerName));
    return Activator.CreateInstance(controllerType) as IController;
}
于 2009-05-11T17:10:29.107 回答
9

是的,你可以,这很好,我自己也用过很多次。

您需要确保的是,当您从 MyController 继承时,您仍然以控制器结束类型名称:

public class FooController :  MyController<Foo>
{ 
 ...
}
于 2009-05-11T16:40:56.970 回答
1

这是实际包含正确答案的asp.net mvc 通用控制器的副本。杰夫弗里茨的回答绝对不正确。创建您自己的 IControllerFactory 不会超过 ExpressionHelper.GetRouteValuesFromExpression 的限制,这会产生您看到的错误。每当您调用 RedirectToAction、BuildUrlFromExpression、ActionLink、RenderAction、BeginForm 以及任何调用这些方法的任何方法时,实现您自己的 IControllerFactory 仍然会给您留下错误。

令我感兴趣的是,Microsoft 的“约定限制”已经由在 ExpressionHelper.GetRouteValuesFromExpression 方法中的类型上放置的约束“where TController : Controller”强制执行。没有泛型将永远满足约定验证:

string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
    throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}

除非它被以“Controller”结尾的类继承,因为 typeof(AnyGeneric).Name 永远不会以“Controller”结尾。

于 2012-10-22T06:49:07.487 回答
1

默认控制器工厂在尝试查找将请求分派到的控制器时使用控制器名称周围的“约定”。如果需要,您可以覆盖此查找功能,然后可以允许您的通用控制器工作。

这篇 MSDN 文章...

http://msdn.microsoft.com/en-us/magazine/dd695917.aspx

...对正在发生的事情有很好的记录。

于 2009-05-11T16:32:35.613 回答
0

如果我是你,我会获取MVC 源并使用源代码创建一个测试 MVC 项目,这样你就可以检查异常是在哪里生成的,看看你可以对你的通用想法和强制执行的“*控制器”命名约定做些什么.

于 2009-05-11T16:37:51.687 回答