AcceptAjaxAttribute 可能是这里需要的;但是,我想提出一种不同的方式来思考这个问题。
并非所有的 Ajax 请求都是平等的。 Ajax 请求可能试图完成以下任何事情:
- 将 JSON 数据绑定到丰富的网格(如 jqGrid);
- 解析/转换 XML 数据,例如 RSS 提要;
- 将部分 HTML 加载到页面的某个区域;
- 异步加载脚本(
google.load 可以做到);
- 处理来自客户端的单向消息;
- 可能还有一些我忘记了。
当您仅基于IsAjaxRequest 方法“选择”特定的“替代操作”时,您会将一些非常通用的东西(异步请求)与服务器上的特定功能联系起来。它最终会让你的设计更脆弱,也让你的控制器更难进行单元测试(尽管有办法做到这一点,你可以模拟上下文)。
一个设计良好的动作应该是一致的,它应该只关心请求是为了什么而不是如何 em> 已提出请求。有人可能会指出像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 等类的存在是因为他们希望一些开发人员使用请求检测方法。但在对这两种方法进行了大量试验后,我发现这种方式非常更容易推理,因此更容易正确设计/编码。