2009-11-01 1 views
1

Рассмотрим MapRoute:Пользовательские объекты в качестве аргументов в методах контроллеров, определенных MapRoutes

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

И это метод контроллера:

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 
    } 
} 

Вот сценарии URL

  • Home/Index/1 пропадут случай 1
  • Home/Index/1.html пойдет к случаю 1
  • Home/Index/1.json будет идти к случаю 2

Это хорошо работает. Но я ненавижу проверку строк. Как бы реализовать параметр enum, который будет использоваться в качестве параметра resultFormat в методе контроллера?


Некоторые псевдокод объяснить основную идею:

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

MapRoute:

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

Метод контроллера подписи:

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

ответ

0

Это ActionFilter я придумал:

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 
     }; 
    } 
} 
3

ИМХО формат ответа является перекрестная озабоченность, и это не контроллер, чтобы возиться с ним. Я хотел бы предложить вам написать ActionFilter для этой работы:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 
public sealed class RespondToAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     var resultFormat = filterContext.RouteData.Values["resultFormat"] as string ?? "html"; 
     ViewResult viewResult = filterContext.Result as ViewResult; 
     if (viewResult == null) 
     { 
      // The controller action did not return a view, probably it redirected 
      return; 
     } 
     var model = viewResult.ViewData.Model; 
     if (string.Equals("json", resultFormat, StringComparison.OrdinalIgnoreCase)) 
     { 
      filterContext.Result = new JsonResult { Data = model }; 
     } 
     // TODO: you could add some other response types you would like to handle 
    } 
} 

который затем упрощает ваши действия контроллера немного:

[RespondTo] 
public ActionResult Index(int id) 
{ 
    var messages = new string[0]; 
    if (id > 0) 
    { 
     // TODO: Fetch messages from somewhere 
     messages = new[] { "message1", "message2" }; 
    } 
    return View(messages); 
} 

ActionFilter многоразовый компонент, который можно применить к другим действиям.

+0

Я не могу получить ваш пример кода для работы. Я разместил здесь новый вопрос: http://stackoverflow.com/questions/1662216/return-jsonresult-using-an-actionfilter-on-a-controller Было бы здорово, если бы вы посмотрели – roosteronacid

+0

Какие конкретные проблемы у вас есть? Как было предложено в качестве ответа в другом вопросе, вам нужно переопределить OnActionExecuted вместо метода OnResultExecuting, потому что последний работает до действия контроллера, и модель всегда будет «null». –

0

Ваш псевдокод будет работать правильно. По умолчанию ModelBinder автоматически преобразует строку в URL-адрес в Model.ResultFormat enum. Но было бы лучше сделать ActionFilter, как сказал Дарин Димитров.