考虑一下这个MapRoute:
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
}
}
以下是网址方案
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:
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 :(得分: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是一个可以重用的组件,可以应用于其他操作。
答案 1 :(得分:0)
您的伪代码将正常运行。默认的ModelBinder会自动将url中的字符串转换为Models.ResultFormat枚举。 但正如Darin Dimitrov所说,制作ActionFilter会更好。
答案 2 :(得分: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
};
}
}