原文地址:Defining Routes using Regular Expressions in ASP.NET MVC
貌似是很老很老的帖子,最近要用正则弄路由,顺手翻了。
把玩一阵ASP.NET MVC Framework beta2之后,我对路由功能感觉比较失望。现在是用一个请求字符串设置一条路由信息, 映射为Controller, Action, 以及Action所需要的参数。在大多数情况下工作起来没有问题,但是在比较复杂的情况下让人比较郁闷。
Scott Guthrie曾经在他的帖子中回答了他们为什么不使用正则表达式来定义路由信息,声称因为大多数人不会用,不过他承诺以后可能会作为一个备选方案,但是既然我们可以实现的话,为啥要等呢?这是我的RegexRoute类,很快很丑陋:
public class RegexRoute : Route { private readonly Regex _urlRegex; public RegexRoute(string urlPattern, IRouteHandler routeHandler) : this(urlPattern, null, routeHandler) { } public RegexRoute(string urlPattern, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(null, defaults, routeHandler) { _urlRegex = new Regex(urlPattern, RegexOptions.Compiled); } public override RouteData GetRouteData(HttpContextBase httpContext) { string requestUrl = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo; Match match = _urlRegex.Match(requestUrl); RouteData data = null; if (match.Success) { data = new RouteData(this, RouteHandler); // add defaults first if (null != Defaults) { foreach (var def in Defaults) { data.Values[def.Key] = def.Value; } } // iterate matching groups for (int i = 1; i < match.Groups.Count; i++) { Group group = match.Groups[i]; if (group.Success) { string key = _urlRegex.GroupNameFromNumber(i); if (!String.IsNullOrEmpty(key) && !Char.IsNumber(key, 0)) // only consider named groups { data.Values[key] = group.Value; } } } } return data; } }
顺便说一下,把路由使用正则表达式的方式定义,给我们带来了很爽的“副作用”,允许我们执行验证,比如某种并不必要的约束。
routes.Add(new RegexRoute(@"^Books/((?<ssn>[\d]{3}(-?)[\d]{2}\1[\d]{4})|(?<query>.+)?)$", new MvcRouteHandler()) { Defaults = new RouteValueDictionary(new { controller = "Book", action = "Find" }) });
上面的路由把请求分隔成两部分,一部分通过ssn选择书籍,另一部分用于通过书名搜索,我想演示使用正则表达式的灵活性,上面的代码中像这样的url请求“mysite.com/Books/Last+Argument+Of+Kings”和“mysite.com/Books/0575077905”都可以用过这个路由映射信息找到相应的action:Find(),像这样定义:
public class BookController : Controller { public void Find(string query, int? ssn) { // ... gets the book by ssn if present, otherwise searches using the query } }
虽然可以使用正则,我对路由仍然不是100%满意,它不允许我重载controll action(现在的版本可以了),上面的示例中,我宁愿弄2个不同的查找方法:Find(string query)和Find(int ssn),通过路由信息分析请求之后调用不同的action,但是MvcRouteHandler却不知道怎么解决这个问题,只晓得抛异常。