关于asp.net mvc:MVC路由中的控制器类别? (在单独的命名空间中重复的控制器名称)

关于asp.net mvc:MVC路由中的控制器类别? (在单独的命名空间中重复的控制器名称)

Categories of controllers in MVC Routing? (Duplicate Controller names in separate Namespaces)

我正在寻找以下情况的一些路由示例或示例:

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

因此,在进行产品搜索商店的情况下,您将拥有:

1
2
3
4
5
public class ProductsController: Controller
{
    public ActionResult Search(string id) // id being the search string
    { ... }
}

假设您有几家商店要这样做,并且始终如一地想要,那么有什么办法可以做到:{category} / {controller} / {action} / {id}

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

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

还是会归结为:

1
2
3
4
5
6
7
8
9
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 <-不起作用-因为不允许使用搜索控制器。


实际上,我什至没有通过搜索找到它,而是通过在这个问题中浏览ASP.NET论坛发现的。

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

但是从这里,您可以在控制器下放置一个目录,因此,如果您的控制器是" MyWebShop.Controllers",则将放置目录" Shop1",而名称空间将是" MyWebShop.Controllers.Shop1"

然后工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    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            
        });
    }

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


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

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

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

  • ASP.NET MVC中单独程序集中的视图
  • asp.net mvc-子文件夹

另一条路线,但是可能需要做出一些妥协,将是使用新的AcceptVerbs属性。查看此问题以获取更多详细信息。我尚未使用此新功能,但这可能是另一条路线。


推荐阅读