在ASP.NET MVC中检查Ajax请求和返回Json结果的好方法

时间:2012-03-29 18:53:03

标签: ajax asp.net-mvc

我想让我在控制器中的操作更加灵活。我的意思是共同的行动通常会返回:

...
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传递给该过滤器...

感谢您提出任何建议

2 个答案:

答案 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;
        }
    }

请注意,此方法意味着您将从操作返回相同的模型。是否选择在“正常”请求中使用视图中的结果对象取决于您。