提问人:Fabian Vilers 提问时间:12/30/2010 最后编辑:CinCoutFabian Vilers 更新时间:10/5/2023 访问量:14316
ASP.NET MVC 正则表达式路由约束
ASP.NET MVC regex route constraint
问:
我在尝试在路由上设置的特定约束时遇到了问题。我的 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 是符合我要求的标题的预制字符串(仅小写,空格替换为破折号)。
问题是,当我点击链接时,没有调用正确的控制器和方法,它落在下一个错误的路由上。
作为记录,我在 MVC 2 ASP.NET。
有人有想法吗?
答:
您可以尝试传递整个路由字符串“{id}-{title}”,并在字符串进入您的操作之前手动解析该字符串,方法是执行类似于 Phil Haack 的 slug to id actionfilter 属性 - link
希望这会有所帮助。
评论
路由中的几个字符是“特殊”的,将拆分 - 和 / 等参数。可能是路由中的额外 -s 导致它失败。尝试这样做,使标题包含以下所有内容。"{id}-{*title}"
更新
上面的答案是当你在喝够咖啡之前继续使用 StackOverflow 时会发生什么。
我们在处理用户上传的文件的文件名时遇到了同样的问题,路由包含“-”作为分隔符,但也可以在后面参数的值中使用,它可以生成正确的 URL,但不匹配。最后,我编写了一个 SpecialFileRoute 类来处理这个问题并注册了此路由。虽然有点丑,但确实如此。
请注意,我保留了旧式的 MVC 路由来生成 URL,我正在尝试让它正确地完成它,但这是稍后再回来的东西。
/// <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 模式、正则表达式和值硬编码,尽管它应该给你一个开始。
评论
你不会有一个好时机,用一个字符来分隔ID与标题,这也是标题模式的一部分。如果可以的话,我建议只使用。{id}/{title}
评论