tags:

views:

55

answers:

3

The name is pretty confusing probably. I have a requirement where a URL must be name friendly to represent dates (schedule/today, schedule/tomorrow etc). I don't want to clutter my route mappings with DateTime.Now, DateTime.Now.AddDays(1) etc for different parameters so I decided to create routes that map to an action of the same name:

routes.MapRoute(RouteNames.ScheduleToday, "schedule/today", new { controller = "Schedule", action = "Today" });
routes.MapRoute(RouteNames.ScheduleTomorrow, "schedule/tomorrow", new { controller = "Schedule", action = "Tomorrow" });

The idea for the actions is that I'd like to be able to call the Today() action but actually call the List(DateTime date) action with, for example, DateTime.Now as the date parameter.

This works great like this:

public ActionResult Today()
{
    return this.List(DateTime.Now);
}

public ViewResult List(DateTime date)
{
    this.ViewData["Date"] = date;
    return this.View("List");
}

I'd like to be able to call this.View() instead of this.View("List"). Is this possible other than what I've posted above? It seems as though the view that is rendered matches the name of the first action that is called since the only way to get this to work is to explicitly render the List view.

+1  A: 

I'm not aware of any way to make the parameterless View() return a view other than the one that matches the name of the first action method. But what about this approach to solve your issue without putting DateTime.Now in your route mappings - if you define your route mappings like this:

routes.MapRoute(RouteNames.ScheduleToday, "schedule/today", new { controller = "Schedule", action = "List", identifier = "today" });
routes.MapRoute(RouteNames.ScheduleTomorrow, "schedule/tomorrow", new { controller = "Schedule", action = "List", identifier = "tomorrow" });

Here we've introduced a new route token called "identifier" which matches what you have in the route. The other thing you could do is define a single route like this:

routes.MapRoute(RouteNames.ScheduleToday, "schedule/{identifier}", new { controller = "Schedule", action = "List" });

But in that case, you'd want a route constraint to constrain your {identifier} token to only your valid values that you support. With these routes in place, you can simply create a custom ActionFilterAttribute which has the single responsibility for setting up dates.

Something like this:

public class DateSelectorAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var identifier = filterContext.RouteData.Values["identifier"] as string;
        switch (identifier)
        {
            case "today":
                filterContext.ActionParameters["date"] = DateTime.Now;
                break;
            case "tomorrow":
                filterContext.ActionParameters["date"] = DateTime.Now.AddDays(1);
                break;
        }
    }
}

Now your List() method can just look like this:

[DateSelector]
public ActionResult List(DateTime date)
{
    this.ViewData.Model = date;
    return this.View();
}

And as a side note, I realized setting up the DateTime.Now in the routes wouldn't work anyway because that would only get called at application start up, effectively caching the date values. The action filter is a better approach because it gets called real-time and gives you the accurate date.

Hope this helps.

Steve Michelotti
@Steve - Yeah thanks for the idea but I think it's really over-complicating what needs to be done. Calling the `this.View("List")` is sufficient.
TheCloudlessSky
A: 

What you are doing is wrong in the way you redirect to another controller action from Today(). You should be using one of the RedirectToAction() overloads. That way you won't have to specify a View in the List() action. And you can provide DateTime as a route value to RedirectToAction().

mare
@mare - Yeah I tried that too but the problem is that it'll actually redirect the URL as well and will put the date *in* the URL (which is ugly since I want to keep them friendly).
TheCloudlessSky
A: 

I still can't find why the first action that is called matches the view and not the last action (perhaps I'll dig into the source). For the time being I'll stick with what I have since there's no reason to over-complicate things.

TheCloudlessSky