Search code examples
c#asp.net-mvcmaproute

Custom objects as arguments in controller methods defined by MapRoutes


Consider this MapRoute:

MapRoute(
    "ResultFormat",
    "{controller}/{action}/{id}.{resultFormat}",
    new { controller = "Home", action = "Index", id = 0, resultFormat = "json" }
);

And it's controller method:

public ActionResult Index(Int32 id, String resultFormat)
{
    var dc = new Models.DataContext();

    var messages = from m in dc.Messages where m.MessageId == id select m;

    if (resultFormat == "json")
    {
        return Json(messages, JsonRequestBehavior.AllowGet); // case 2
    }
    else
    {
        return View(messages); // case 1
    }
}

Here's the URL scenarios

  • Home/Index/1 will go to case 1
  • Home/Index/1.html will go to case 1
  • Home/Index/1.json will go to case 2

This works well. But I hate checking for strings. How would implement an enum to be used as the resultFormat parameter in the controller method?


Some pseudo-code to explain the basic idea:

namespace Models
{
    public enum ResponseType
    {
        HTML = 0,
        JSON = 1,
        Text = 2
    }
}

The MapRoute:

MapRoute(
    "ResultFormat",
    "{controller}/{action}/{id}.{resultFormat}",
    new {
        controller = "Home",
        action = "Index",
        id = 0,
        resultFormat = Models.ResultFormat.HTML
    }
);

The controller method signature:

public ActionResult Index(Int32 id, Models.ResultFormat resultFormat)

Solution

  • This is the ActionFilter I came up with:

    public sealed class AlternateOutputAttribute :
                        ActionFilterAttribute, IActionFilter
    {
        void IActionFilter.OnActionExecuted(ActionExecutedContext aec)
        {
            ViewResult vr = aec.Result as ViewResult;
    
            if (vr == null) return;
    
            var aof = aec.RouteData.Values["alternateOutputFormat"] as String;
    
            if (aof == "json") aec.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = vr.ViewData.Model,
                ContentType = "application/json",
                ContentEncoding = Encoding.UTF8
            };
        }
    }