【问题标题】:ASP.NET MVC regex route constraintASP.NET MVC 正则表达式路由约束
【发布时间】:2011-06-01 11:14:24
【问题描述】:

我在尝试在路线上设置特定约束时遇到问题。我的 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 是符合我要求的标题的预制字符串(仅小写,空格替换为破折号)。

问题是,当我点击链接时,没有调用正确的控制器和方法,它掉到了错误的下一个路由。

作为记录,我使用的是 ASP.NET MVC 2。

有人有想法吗?

【问题讨论】:

  • 最后,我们用取消划线将 ID 与标题分开。我仍然想知道为什么这不起作用,但它不再阻塞。感谢您的帮助!

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


【解决方案1】:

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

希望这会有所帮助。

【讨论】:

  • 我之前读过那篇博文,但是当我可以拆分路线信息时,我发现它有点矫枉过正。由于我的 URL 可以从路由创建但不能解析为路由,我正在考虑 MVC 中的某种错误。
  • 啊,很公平。会有另一个想法:-)
【解决方案2】:

路由中的几个字符是“特殊的”,会拆分-和/等参数。可能是路由中额外的 -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 模式、正则表达式和值是硬编码的。

【讨论】:

  • 感谢您提供信息,但我们不能在包含多个部分的句段中使用统称 (*) 参数。
  • 当然可以。不久前我遇到了同样的问题
猜你喜欢
  • 2019-02-10
  • 1970-01-01
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-09
  • 1970-01-01
  • 2016-11-21
相关资源
最近更新 更多