ASP.NET MVC正则表达式路由约束

时间:2010-12-30 08:57:15

标签: regex asp.net-mvc-2 constraints routes

我正在尝试在路线上设置特定约束。我的URL必须如下所示:http://hostname/id-my-title-can-be-that-long其中id仅由数字组成,标题为带有破折号分隔符的小写字符。 id和标题也用短划线分隔。例如:http://hostname/123-my-title

这是我的路线定义:

routes.MapRoute(
    "Test",
    "{id}-{title}",
    new { controller = "Article", action = "Index" },
    new { id = @"(\d)+", title = @"([a-z]+-?)+" }
);

使用html帮助程序正确生成URL:

<%: Html.ActionLink("My link", "Index", "Article", new { id = Model.IdArticle, title = Model.UrlTitle }, null) %>

当然,Model.IdArticle是一个Int32,而Model.UrlTitle是我的标题的预先形成的字符串,符合我的要求(仅限小写,空格由短划线替换)。

问题是,当我按照链接时,正确的控制器&amp;方法未被调用,它落入下一个错误的路径。

对于记录,我使用的是ASP.NET MVC 2.

有人有想法吗?

提前致谢, 费边

2 个答案:

答案 0 :(得分:0)

您可以尝试传递整个路径字符串“{id} - {title}”并在进入您的操作之前手动解析字符串,方法是执行与Phil Haack的slug到id actionfilter属性类似的操作 - link

希望这有帮助。

答案 1 :(得分:0)

路线中的几个字符是“特殊的”,并将分割参数,如 - 和/。可能是路由中的额外-s导致其失败。请尝试"{id}-{*title}",因为这会使标题包含随后的所有内容。

<强>更新

上面的答案是当你喝足够的咖啡之前进入StackOverflow会发生什么。

我们遇到了同样的问题,处理用户上传的文件的文件名,路由包括' - '作为分隔符,但也可以在后面的参数中的值中使用,它可以生成正确的URL但不会'匹配它。最后,我写了一个SpecialFileRoute类来处理这个问题并注册了这条路线。虽然它有点难看,但是做到了。

请注意,我保留了用于生成URL的旧式MVC路由,我正在玩这个以便正确地执行此操作,但这是稍后回来的事情。

    /// <summary>
/// Special route to handle hyphens in the filename, a catchall parameter in the commented route caused exceptions
/// </summary>
public class SpecialFileRoute : RouteBase, IRouteWithArea
{
    public string Controller { get; set; }
    public string Action { get; set; }
    public IRouteHandler RouteHandler = new MvcRouteHandler();
    public string Area { get; private set; }

    //Doc/{doccode} - {CatNumber}.{version} - {*filename},

    public SpecialFileRoute(string area)
    {
        Area = area;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        string url = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2);
        var urlmatch = Regex.Match(url, @"doc/(\w*) - (\d*).(\d*) - (.*)", RegexOptions.IgnoreCase);
        if (urlmatch.Success)
        {
            var routeData = new RouteData(this, this.RouteHandler);

            routeData.Values.Add("doccode", urlmatch.Groups[1].Value);
            routeData.Values.Add("CatNumber", urlmatch.Groups[2].Value);
            routeData.Values.Add("version", urlmatch.Groups[3].Value);
            routeData.Values.Add("filename", urlmatch.Groups[4].Value);
            routeData.Values.Add("controller", this.Controller);
            routeData.Values.Add("action", this.Action);
            return routeData;
        }
        else
            return null;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        if (values.ContainsKey("controller") && (!string.Equals(Controller, values["controller"] as string, StringComparison.InvariantCultureIgnoreCase)))
            return null;
        if (values.ContainsKey("action") && (!string.Equals(Action, values["action"] as string, StringComparison.InvariantCultureIgnoreCase)))
            return null;
        if ((!values.ContainsKey("contentUrl")) || (!values.ContainsKey("format")))
            return null;
        return new VirtualPathData(this, string.Format("{0}.{1}", values["contentUrl"], values["format"]));
    }
}

路线添加如下:

context.Routes.Add(new SpecialFileRoute(AreaName) { Controller = "Doc", Action = "Download" });

如上所述,这有点难看,当我有时间时,我想做很多工作来改进它,但它解决了将URL拆分为所需参数的问题。它与url模式,Regex和Values硬编码的这一条路线的特定要求密切相关,虽然它应该给你一个开始。