2010-02-27 17 views
1

我已經爲簡單的博客定義了以下路由。嘗試創建友好的&「可破解的」URL時遇到問題使用Url.Action()

routes.MapRoute(
    "Blog", 
    "blog/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Index" }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

的網址應該能夠 「被破解」,以實現以下目標:

我已經創建了一個很好地處理這個動作的控制器。不過,我在使用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

我寧願喜歡它來生成網址看起來像上面列表中的網址。

http://abc.com/blog/2010/02/21

有什麼辦法,我可以使用Url.Action()Html.ActionLink()產生在我想要的網址格式?

回答

3

問題在於您傳遞給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 = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

而在你的控制器動作檢查,如果月或日爲0,其中你應該顯示整個月或整年的情況。

+0

你釘了它。感謝您的回答。它像一個魅力。 – jessegavin 2010-02-28 21:40:42

0

我看到你遇到的另一個問題是,你需要幾個其他路由條目和適當的默認值來處理這些其他情況。

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 = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

routes.MapRoute(
    null, 
    "blog/{year}", 
    new { controller = "Blog", action = "Index", month = 00, day = 00 }, 
    new { year = @"\d{4}" } 
); 

routes.MapRoute(
    null, 
    "blog/{year}/{month}", 
    new { controller = "Blog", action = "Index", day = 00 }, 
    new { year = @"\d{4}", month = @"\d{2}"} 
); 

有幾種方式來處理這種情況,但現在在你的博客控制器和索引操作可以按年,月,日過濾帖子結果。

簡單的例子:

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

我會建議,而不是有三個單獨的路線只使用默認值爲月和日。我已經更新了我的答案以包含此內容。 – Eilon 2010-02-28 00:36:11

+0

+1爲簡潔和整體迷人。如果我在一些相當沉重的MVC使用後保持誠實,我不知道這是可能的。我認爲如果路線被接受,無論發生什麼,它都會發送默認值,但經過快速測試,您的速記解決方案效果很好。 – 2010-02-28 03:44:51

+0

您不需要多條路線即可完成此操作。我在問題描述中顯示的路線非常有效。 (我的問題更多地涉及Url.Action()如何生成一個url來匹配該路線。) – jessegavin 2010-03-02 19:30:24

0

你不必寫入所有條件新方法。我的意思是你可以這樣做;

例如。爲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。它逐步檢查參數,年 - >月 - >日。如果用戶不在querystring中設置任何參數,它將返回所有博客。

+0

這實際上是我已經在做的。我的問題更多地與Url路由相關。 – jessegavin 2010-02-28 21:39:25

+0

是的,我明白你的問題,但已經回答,並且他正在用新方法做。我說過,因爲它可能會幫助你 – cem 2010-03-01 17:11:16