2009-11-01 484 views
1

考慮這個圖路線的控制方法的參數:自定義對象由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

這種運作良好。但我討厭檢查字符串。如何在控制器方法中實現枚舉作爲resultFormat參數?


一些僞代碼來解釋的基本思想:

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

的圖路線:

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

IMHO響應格式是橫切關注,並不是控制器惹的禍。我建議你寫這個作業的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 2009-11-02 16:17:38

+0

什麼特殊問題你有嗎?正如您在其他問題中提出的答案,您需要重寫OnActionExecuted而不是OnResultExecuting方法,因爲後者在控制器操作之前運行,並且模型始終爲'null'。 – 2009-11-02 19:02:47

0

您的僞代碼將正常工作。默認的ModelBinder自動將URL中的字符串轉換爲Models.ResultFormat枚舉。 但是,如果說達林季米特洛夫說要製作ActionFilter會更好。