【问题标题】:Categories of controllers in MVC Routing? (Duplicate Controller names in separate Namespaces)MVC 路由中的控制器类别? (在单独的命名空间中重复的控制器名称)
【发布时间】:2010-09-07 18:38:53
【问题描述】:

我正在为以下场景寻找一些路由示例或示例:

做事的一般例子是:{controller}/{action}/{id}

因此,在为您拥有的商店进行产品搜索的场景中:

public class ProductsController: Controller
{
    public ActionResult Search(string id) // id being the search string
    { ... }
}

假设您有几家商店可以做到这一点,并且您一直希望这样做,那么有什么办法可以做到:{category}/{controller}/{action}/{id}

这样您就可以对特定商店进行特定搜索,但对不同商店使用不同的搜索方法?

(如果您要求商店名称的优先级高于 url 中的函数本身)

还是归结为:

public class ProductsController: Controller
{
    public ActionResult Search(int category, string id) // id being the search string
    { 
        if(category == 1) return Category1Search();
        if(category == 2) return Category2Search();
        ...
    }
}

这可能不是一个很好的例子,但基本上这个想法是使用相同的控制器名称,因此在几个不同的场景中都有一个简单的 URL,或者你有点坚持要求唯一的控制器名称,没有办法将它们放在稍微不同的命名空间/目录中?

编辑添加:

我想要这个的另一个原因是因为我可能想要一个包含类别的 url,并且某些控制器只能在某些类别下工作。

IE:

/this/search/items/search+term

/that/search/items/search+term

【问题讨论】:

  • 1.0 版本中的“区域”概念是否解决了这个问题?

标签: asp.net-mvc routing controller


【解决方案1】:

实际上我什至不是通过搜索找到的,而是通过浏览this question 中的 ASP .NET 论坛。

使用它,您可以在命名空间的任何部分下拥有同名的控制器,只要您限定哪些路由属于哪些命名空间(如果需要,每个路由可以有多个命名空间!)

但是从这里开始,你可以在你的控制器下放置一个目录,所以如果你的控制器是“MyWebShop.Controllers”,你会放置一个“Shop1”的目录,命名空间是“MyWebShop.Controllers.Shop1”

然后这个工作:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        var shop1namespace = new RouteValueDictionary();
        shop1namespace.Add("namespaces", new HashSet<string>(new string[] 
        { 
            "MyWebShop.Controllers.Shop1"
        }));

        routes.Add("Shop1", new Route("Shop1/{controller}/{action}/{id}", new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(new
            {
                action = "Index",
                id = (string)null
            }),
            DataTokens = shop1namespace
        });

        var shop2namespace = new RouteValueDictionary();
        shop2namespace.Add("namespaces", new HashSet<string>(new string[] 
        { 
            "MyWebShop.Controllers.Shop2"
        }));

        routes.Add("Shop2", new Route("Shop2/{controller}/{action}/{id}", new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(new
            {
                action = "Index",
                id = (string)null
            }),
            DataTokens = shop2namespace
        });

        var defaultnamespace = new RouteValueDictionary();
        defaultnamespace.Add("namespaces", new HashSet<string>(new string[] 
        { 
            "MyWebShop.Controllers"
        }));

        routes.Add("Default", new Route("{controller}/{action}/{id}", new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
            DataTokens = defaultnamespace            
        });
    }

唯一的另一件事是它将引用仍在基目录中的视图,因此如果您将视图放入目录以匹配,当您将视图名称返回到控制器中时,您必须将视图名称放入其中。

【讨论】:

    【解决方案2】:

    在不妥协的情况下做到这一点的最佳方法是通过继承 IControllerFactory 来实现您自己的 ControllerFactory。您将实现的 CreateController 方法处理创建控制器实例以处理 RouteHandler 和 ControllerActionInvoker 的请求。约定是在创建控制器时使用控制器的名称,因此您需要覆盖此功能。这将是您放置基于路由创建控制器的自定义逻辑的位置,因为您将拥有多个具有相同名称但位于不同文件夹中的控制器。然后你需要在应用启动时注册你的自定义控制器工厂,就像你的路由一样。

    您需要考虑的另一个方面是在创建控制器时查找视图。如果您打算对所有这些视图使用相同的视图,那么您不必做任何与所使用的约定不同的事情。如果您还计划组织视图,那么您还需要创建自己的 ViewLocator 并在控制器工厂中创建时将其分配给控制器。

    为了了解代码,我在 SO 上回答了一些与此问题相关的问题,但这个问题在某种程度上有所不同,因为控制器名称是相同的。我提供了链接供参考。

    另一条路线,但可能需要一些妥协,将使用新的 AcceptVerbs 属性。查看此question 了解更多详情。我还没有玩过这个新功能,但它可能是另一条路线。

    【讨论】:

      猜你喜欢
      • 2018-03-27
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多