尝试创建友好且“可破解”的 url 时使用 Url.Action() 时遇到问题
Posted
技术标签:
【中文标题】尝试创建友好且“可破解”的 url 时使用 Url.Action() 时遇到问题【英文标题】:Trouble using Url.Action() when trying to create friendly & "hackable" urls 【发布时间】:2011-01-21 20:33:53 【问题描述】:我为一个简单的博客定义了以下路线。
routes.MapRoute(
"Blog",
"blog/year/month/day",
new controller = "Blog", action = "Index" ,
new year = @"\d4", month = @"\d2", day = @"\d2"
);
网址应该能够“破解”以完成以下操作:
http://abc.com/blog/2010 -> 显示所有 2010 年的帖子 http://abc.com/blog/2010/01 -> 显示 2010 年 1 月的所有帖子 http://abc.com/blog/2010/01/25 -> 显示 2010 年 1 月 25 日的所有帖子我创建了一个控制器,可以很好地处理这个动作。但是,我无法使用Url.Action()
在我的视图中创建链接。
例如这个...
var d = new DateTime(2010, 1, 25);
Url.Action("Index", "Blog", new year=d.Year, month=d.Month, day=d.Day );
...生成一个如下所示的 url:
http://abc.com/blog?year=2010&month=2&day=21
我希望它生成一个看起来像上面列表中的 url 的 url。
http://abc.com/blog/2010/02/21
有什么方法可以使用Url.Action()
或html.ActionLink()
以我想要的格式生成网址?
【问题讨论】:
【参考方案1】:问题在于您传递给Url.Action
的月份是个位数的月份,因此与路线定义上的月份限制不匹配。约束通常不仅在传入的 URL 上运行,而且在生成 URL 时也运行。
解决方法是在月份手动调用 .ToString() 并将其格式化为两位数。你也需要为这一天做同样的事情。对于这一年来说,这不是问题,因为我们一生中的所有年份都是四位数。
这是格式化数字的示例代码:
int month = 2;
string formattedMonth = month.ToString("00", CultureInfo.InvariantCulture);
// formattedMonth == "02"
请注意,在手动格式化数字时,您必须使用不变文化,这样不同的文化和语言就不会影响它的格式。
您还需要设置月份和日期的默认值,以便 URL 中不需要它们:
routes.MapRoute(
"Blog",
"blog/year/month/day",
new controller = "Blog", action = "Index", month = "00", day = "00" ,
new year = @"\d4", month = @"\d2", day = @"\d2"
);
并在您的控制器操作中检查月份或日期是否为 0,在这种情况下,您应该显示整月或整年。
【讨论】:
你成功了。感谢您的回答。它就像一个魅力。【参考方案2】:我看到您遇到的另一个问题是,您需要几个具有适当默认值的其他路由条目来处理其他场景。
“http://abc.com/2010”将不匹配“blog/year/month/day”。这是一个非常具体的路线,需要三个参数(带有约束)来匹配。为了接受这些其他路线,您需要按照以下方式创建其他路线条目:
routes.MapRoute(
null,
"blog",
new controller = "Blog", action = "Index", year = 0000, month = 00, day = 00 ,
new year = @"\d4", month = @"\d2", day = @"\d2"
);
routes.MapRoute(
null,
"blog/year",
new controller = "Blog", action = "Index", month = 00, day = 00 ,
new year = @"\d4"
);
routes.MapRoute(
null,
"blog/year/month",
new controller = "Blog", action = "Index", day = 00 ,
new year = @"\d4", month = @"\d2"
);
有几种方法可以处理这种情况,但现在在您的博客控制器和索引操作中,您可以按年、月、日过滤帖子结果。
快速示例:
if(year == 0000 && month == 00 && day == 00)
var posts = postsRepository.GetAllPost();
else if(year != 0000 && month == 00 && day == 00)
var posts = postsRepository.GetPostsByYear(year);
...
【讨论】:
我建议不要使用三个单独的路由来仅使用月份和日期的默认值。我已更新我的答案以包含此内容。 +1 简洁和整体令人敬畏。老实说,在大量使用 MVC 之后,我不知道这是可能的。我认为如果路由被接受,无论如何它都会发送默认值,但经过快速测试,您的速记解决方案效果很好。 您不需要多条路线来完成此操作。我在问题描述中展示的路线非常有效。 (我的问题与 Url.Action() 如何生成与该路由匹配的 url 更相关。)【参考方案3】:您不必为所有条件编写新方法。我的意思是你可以这样做;
例如。用于 NHibernate。
public IList<Blog> GetBlogs(int? day, int? month, int? year)
IQueryable<Blog> iQBlog = Session.Linq<Blog>();
if (year.HasValue)
iQBlog = iQBlog.Where(b => b.Year == year);
if (month.HasValue)
iQBlog = iQBlog.Where(b => b.Month == month);
if (day.HasValue)
iQBlog = iQBlog.Where(b => b.Day == day);
return iQBlog.ToList();
ps。它正在逐步检查参数,年 -> 月 -> 日。如果用户没有在查询字符串中设置任何参数,它将返回所有博客。
【讨论】:
这实际上是我已经在做的事情。我的问题与 URL 路由更相关。 是的,我理解你的问题,但已经回答了,她/他正在用新的方法来做。我这么说是因为它可能对你有帮助以上是关于尝试创建友好且“可破解”的 url 时使用 Url.Action() 时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章