【问题标题】:In asp.net mvc is it possible to make a generic controller?在 asp.net mvc 中是否可以制作通用控制器?
【发布时间】:2009-05-11 16:26:01
【问题描述】:

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

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

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

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

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

谢谢!

【问题讨论】:

  • 你到底想通过这个实现什么?当 MyController 被实例化时,它需要知道 T 是什么,无论是通过子类还是它的构造函数。如果你想动态地做到这一点,你需要编写一个 ControllerFactory

标签: asp.net asp.net-mvc generics controller


【解决方案1】:

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

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

您希望/Product/Index 触发MyController&lt;Product&gt;.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;
}

【讨论】:

  • 这很有趣,我正在研究它。谢谢。
  • np...不要忘记,“控制器”命名约定是默认标准。如果您想以其他方式实例化,那就去做吧!编写一个 IControllerFactory 来执行您的标准,而不是 MSFT 的
  • 问题在于,您还需要通用视图模型、通用的绑定和过滤方式、通用验证,这可能是实现它的一项壮举
  • @mare 对于任何大型 api,绑定过滤器的通用方式基本上应该是标准的,尤其是对于像 CRUD 这样的东西
【解决方案2】:

可以,没关系,我自己也用过很多次。

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

public class FooController :  MyController<Foo>
{ 
 ...
}

【讨论】:

  • 我不希望每种类型都有单独的控制器...我想要一个通用控制器来处理多种类型。
  • 我试过这个,当我进入“public void Edit(Foo Item) {...}”时,MVC 不理解 Foo 的类型,但是我在泛型类,所以对象“Item”的所有参数都是初始值!!!
【解决方案3】:

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

这篇 MSDN 文章...

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

...对正在发生的事情进行了很好的记录。

【讨论】:

    【解决方案4】:

    这是asp.net mvc generic controller 的副本,实际上包含正确答案。杰夫弗里茨的回答绝对不正确。创建您自己的 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”结尾。

    【讨论】:

    • 您认为@Iain Holder 的答案是否正确?
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-16
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      • 2018-04-23
      • 1970-01-01
      相关资源
      最近更新 更多