Reputation: 75670
I've defined the following route for a simple blog.
routes.MapRoute(
"Blog",
"blog/{year}/{month}/{day}",
new { controller = "Blog", action = "Index" },
new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" }
);
The url should be able "hackable" to accomplish the following:
I have created a controller which handles this action quite nicely. However I am having trouble creating links in my views using Url.Action()
.
For example this...
var d = new DateTime(2010, 1, 25);
Url.Action("Index", "Blog", new { year=d.Year, month=d.Month, day=d.Day} );
...generates a url like that looks like this:
I would rather like it to generate a url that looks like the urls in the list above.
Is there any way I can use Url.Action()
or Html.ActionLink()
to generate urls in the format I desire?
Upvotes: 1
Views: 969
Reputation: 1911
You dont have to write new method for all condition. I mean you can do it with this;
eg. for 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. It's checking parameters step by step, year -> month -> day. If user doesnt set any parameters in querystring, it will return all blogs.
Upvotes: 0
Reputation: 25704
The issue there is that the month you're passing in to Url.Action
is a single-digit month, and thus doesn't match the month constraint on the route definition. Constraints are typically run not only on incoming URLs but also when generating URLs.
The fix would be to manually call .ToString() on the month and format it as a two-digit number. You'll need to do the same for the day as well. For the year it's not an issue since all the years in our lifetimes will be four-digit numbers.
Here's sample code to format numbers:
int month = 2;
string formattedMonth = month.ToString("00", CultureInfo.InvariantCulture);
// formattedMonth == "02"
Please note that when formatting the number manually that you must use the Invariant Culture so that different cultures and languages won't affect how it gets formatted.
You'll also need to set default values for month and day so that they are not required in the 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}" }
);
And in your controller action check if the month or day are 0, in which case you should show an entire month or entire year.
Upvotes: 4
Reputation: 1847
The other issue I see you running into is that you'll need several other route entries with appropriate defaults to handle those other scenarios.
"http://abc.com/2010" will not match "blog/{year}/{month}/{day}". That's a very specific route that requires three parameters (with constraints) to match. In order to accept those other routes you'll need to create other route entries along the lines of:
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}"}
);
There are a few ways to handle this scenario, but now in your Blog controller and your Index action you can filter the posts results by year, month, day.
Quick example:
if(year == 0000 && month == 00 && day == 00)
var posts = postsRepository.GetAllPost();
else if(year != 0000 && month == 00 && day == 00)
var posts = postsRepository.GetPostsByYear(year);
...
Upvotes: 0