我想让我在控制器中的操作更加灵活。我的意思是共同的行动通常会返回:
...
return View("someView");
或者,例如,如果是Ajax:
...
return Json(new {result="ok"});
我想要的是让我的行动更加“多用途”。例如,我基于简单的非Ajax请求创建了我的UI层,然后我决定使它更加用户友好并添加了一些Ajax。这样我就必须纠正一些动作以返回Json。
避免此类事情的最简单(也可能是最差)方法是在每个(或几乎每个)Action中编写以下代码:
if (Request.IsAjaxRequest) {
return Json(new {result="ok"});
}
else {
return View("someView")
}
但当然这种方法完全与DRY的原则相冲突。
所以我想找到实现“多用途”的良好做法。
一种方法是编写一些这样的辅助方法:
public ActionResult CheckForAjax(ActionResult result)
{
return ActionResult(result, Json(new {result="ok"}));
}
public ActionResult CheckForAjax(ActionResult result, Json json)
{
if (Request.IsAjaxRequest) {
return json;
}
else {
return result;
}
}
这样我可以在Actions中调用助手:
return CheckForAjax(View(...));
或
return CheckForAjax(View(...), Json(new {myCustomJson="hi"});
但我不知道这是好方法还是只是重新发明一些自行车:) 也许最好使用动作过滤器?但我不知道如何将自定义Json传递给该过滤器...
感谢您提出任何建议
答案 0 :(得分:6)
老实说,我认为你原来的解决方案没问题,而你的第二个解决方案比第一个更容易违反DRY。您的第二个解决方案非常冗余,并提供了两种方法来完成一项工作,轻松处理。
这不仅是糟糕的风格,而且是可维护性问题。通过将两个函数用于一个目的,每次发生更改时都必须更新这两个函数。为什么你这样做也不是很清楚,这将使其他开发人员难以维护你的代码。
如果你问我,KISS(保持简单愚蠢)比DRY更重要(不要重复自己)。如果您的代码易于理解,那么它就是很好的代码。
答案 1 :(得分:2)
如果从动作返回相同的模型,则:
var model = new {result="ok"}
if (Request.IsAjaxRequest) {
return Json(model);
}
else {
return View("someView", model)
}
您可以轻松编写Actionfilter来执行此操作。示例如下:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
var res = filterContext.Result as ViewResultBase;
if (res == null) { return; }
var jres = new JsonNetResult();
jres.SerializerSettings.Converters.Add(new IsoDateTimeConverter());
jres.Data = res.ViewData.Model;
filterContext.Result = jres;
}
}
请注意,此方法意味着您将从操作返回相同的模型。是否选择在“正常”请求中使用视图中的结果对象取决于您。