AcceptAjaxAttribute
可能是这里需要的;但是,我想提出一种不同的方式来思考这个问题。
并非所有的 Ajax 请求都是平等的。Ajax 请求可能试图完成以下任何事情:
- 将 JSON 数据绑定到丰富的网格(如 jqGrid);
- 解析/转换 XML 数据,例如 RSS 提要;
- 将部分 HTML 加载到页面的某个区域;
- 异步加载脚本(
google.load
可以这样做);
- 处理来自客户端的单向消息;
- 可能还有一些我忘记了。
当您仅基于该IsAjaxRequest
方法“选择”特定的“替代操作”时,您会将一些非常通用的东西 - 异步请求 - 与服务器上的特定功能联系起来。它最终会让你的设计更脆弱,也让你的控制器更难进行单元测试(虽然有办法做到这一点,你可以模拟上下文)。
一个设计良好的动作应该是一致的,它应该只关心请求是为了什么而不是请求是如何提出的。有人可能会指出其他属性,例如AuthorizeAttribute
例外,但我会对过滤器进行区分,大多数情况下,过滤器描述了必须在动作发生“之前”或“之后”发生的行为,而不是“代替”。
说到这里,问题中陈述的目标是一个很好的目标;对于正确描述为不同操作的内容,您绝对应该有不同的方法:
public ActionResult Details(int id)
{
return View("Details", GetDetails(id));
}
public ActionResult JsonDetails(int id)
{
return Json(GetDetails(id));
}
public ActionResult PartialDetails(int id)
{
return PartialView("DetailTable", GetDetails(id));
}
等等。但是,使用 Ajax 操作选择器在这些方法之间进行选择是遵循“优雅降级”的做法,该做法基本上已被渐进增强取代(至少 IMO)。
这就是为什么,虽然我喜欢 ASP.NET MVC,但我大多避开 . AjaxHelper
,因为我发现它不能很好地表达这个概念;它试图对你隐藏太多。我们不再使用“Ajax 表单”或“Ajax 操作”的概念,而是消除区别并坚持使用直接 HTML,然后在我们确定客户端可以处理它时单独注入 Ajax 功能。
这是 jQuery 中的一个示例 - 尽管您也可以在 MS AJAX 中执行此操作:
$(function() {
$("#showdetails").click(function() {
$("#details").load("PartialDetails", { id: <%= Record.ID %> });
return false;
}
});
这就是将 Ajax 注入 MVC 页面所需的全部内容。从一个普通的旧 HTML 链接开始,然后用一个 Ajax 调用覆盖它,该调用转到另一个控制器操作。
现在,如果在您网站的其他地方,您决定要使用网格,但又不想使用部分渲染来破坏页面,您可以编写类似这样的内容(假设您有一个主从页面左侧的“订单”列表和右侧的详细信息表):
$(".detaillink").click(function() {
$('#detailGrid').setGridParam({
url: $(this).attr("href").replace(/\/order\/details/i,
"/order/jsondetails")
});
$("#detailGrid").trigger("reloadGrid");
});
这种方法将客户端行为与服务器行为完全分离。服务器实际上是在对客户端说:如果您想要 JSON 版本,请询问JSON 版本,哦,顺便说一下,如果您知道如何运行,这里有一个脚本可以转换您的链接。 没有动作选择器和方法重载,没有为了运行简单的测试而必须做的特殊模拟,没有混淆哪个动作在什么时候做什么。只需几行 JavaScript。控制器动作简短而甜蜜,正是它们应有的方式。
这不是唯一的方法。显然,AcceptAjaxAttribute
存在诸如此类的类是因为它们希望某些开发人员使用请求检测方法。但是在对两者进行了相当多的试验之后,我发现这种方式更容易推理,因此更容易正确设计/编码。