如何将三个ASP MVC路由合并为一个?

时间:2012-09-01 18:18:57

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

我设置了以下路线:

        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开头,则使用索引操作将

转换为单个路径?

2 个答案:

答案 0 :(得分: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对它们进行装饰,这样就无法通过您的默认路线获取它们,您可能也可以使用它们......

答案 1 :(得分:1)

您仍然可以有三条路线,但通过为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" } }
            );

此外,您可以将其重复用于其他类似情况。希望这有帮助