【问题标题】:How can I combine three ASP MVC routes into one?如何将三个 ASP MVC 路由合二为一?
【发布时间】:2012-09-02 04:31:54
【问题描述】:

我设置了以下路线:

        context.MapRoute(
            "content_article",
            "A{rk}/{title}",
            new { controller = "Server", action = "Article" },
            new { rk = @"^[\dA-Z]{3}$" }
        );

        context.MapRoute(
            "content_contentBlock",
            "C{rk}/{title}",
            new { controller = "Server", action = "ContentBlock" },
            new { rk = @"^[\dA-Z]{3}$" }
        );

        context.MapRoute(
            "content_favoritesList",
            "F{rk}/{title}",
            new { controller = "Server", action = "FavoritesList" },
            new { rk = @"^[\dA-Z]{3}$" }
        );

有没有办法可以结合:

"A{rk}/{title}",
"C{rk}/{title}",
"F{rk}/{title}",

如果 URL 以 A、C 或 F 开头,则进入一个带有 Index 操作的单个路由?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-routing


    【解决方案1】:

    所以,如果我理解正确,您只需要一条路线来覆盖所有三个路线并指向Index 操作吗?如果这是问题而不是答案

    当然可以

    您只需将您的正则表达式稍微更改为此路由定义:

    context.MapRoute(
        "content",
        "{lrk}/{title}",
        new { controller = "Server", action = "Index" },
        new { lrk = @"^[ACF][0-9A-Z]{3}$" }
    );
    

    就是这样。然后通过可能(并希望)执行适当的单独方法的索引操作完成第一个字母的解析。

    public ActionResult Index(string lrk)
    {
        if (string.IsNullOrEmpty(lrk))
        {
            throw new ArgumentException("lrk")
        }
        char first = lrk[0];
        switch(first)
        {
            case 'A':
                return GetArticle(lrk.Substring(1));
            case 'C':
                return GetContent(lrk.Substring(1));
            case 'F':
                return GetFavorites(lrk.Substring(1));
            default:
                return View();
        }
    }
    
    private ActionResult GetArticle(string rk)
    {
        ...
    }
    
    // and other couple
    

    如您所见,这三个方法具有相同的签名,就好像它们是控制器操作一样,但它们不是,因为它们是 private。您可以将它们设置为private 或使用NonActionAttribute 装饰它们,这样它们就不会被您的默认路线拾取,您可能也有...

    【讨论】:

    • 非常感谢。这正是我想做的。
    【解决方案2】:

    您仍然可以拥有三个路由,但通过为 RouteCollection 添加扩展方法来简化它们的定义:

    public class ActionMap : Dictionary<string, string>
        {}
    
        public static class RouteCollectionExtensions
        {
            public static void MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, ActionMap map)
            {
                if(!url.Contains("{action}")) throw new ArgumentException("{action} segment is required", url);
    
                foreach (var actionKey in map.Keys)
                {
                    string routeName = string.Format("{0}_{1}", name, map[actionKey]);
                    string routeUrl = url.Replace("{action}", actionKey);
                    var routeDefaults = new RouteValueDictionary(defaults);
                    routeDefaults["action"] = map[actionKey];
    
                    Route route = new Route(routeUrl, new MvcRouteHandler())
                    {
                        Defaults = routeDefaults,
                        Constraints = new RouteValueDictionary(constraints),
                        DataTokens = new RouteValueDictionary()
                    };
    
                    routes.Add(routeName, route);
                }
            }
        }
    

    现在这些路线的定义如下:

     routes.MapRoute(
                        "content",
                       "{action}{rk}/{title}",
                       new { controller = "Server" },
                       new { rk = @"^[\dA-Z]{3}$" },
                        new ActionMap { { "a", "Article" }, { "c", "ContentBlock" }, { "f", "FavoritesList" } }
                );
    

    您也可以在其他类似情况下重复使用它。希望这会有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-26
      • 2016-04-22
      • 1970-01-01
      • 2014-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多