尝试创建友好且“可破解”的 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() 时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 htaccess 创建 SEO 友好的 url

在 Xampp 中创建友好的 URL

如何创建用户友好的 url,如 ***?

带有 UTF8 字符的友好 URL

如何使用 .htaccess 创建友好的 URL?

.htaccess 用于友好的 URL