我想避免在我的控制器中有很多if Request.IsAjaxRequest()
。我想如果我可以将这个逻辑压缩到ActionFilter,那么在我的应用程序中采用一个约定很容易为可能使用Ajax的任何请求提供第二个动作,同时提供一个回退JavaScript已禁用。
public ActionResult Details(int id)
{
// called normally, show full page
}
public ActionResult Details_Ajax(int id)
{
// called through ajax, return a partial view
}
我最初认为我可以这样做:
public class AjaxRenameAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RouteData.Values["action"] = filterContext.RouteData.Values["action"] + "_Ajax";
}
但这不起作用,因为决定了要调用的动作,然后处理它上面的过滤器。
每次有人调用一个动作时,我真的不想返回一个RedirectResult,将Http请求的数量增加一倍似乎没有意义。
是否有不同的方式将请求路由到其他操作?或者我正在做的事情是不可取的,我应该寻找更好的做事方式?
干杯
答案 0 :(得分:2)
MvcFutures中的AcceptAjaxAttribute怎么样?
答案 1 :(得分:1)
AcceptAjaxAttribute
可能就是这里所需要的;但是,我想提出一种不同的思考方式。
并非所有Ajax请求都是相同的。 Ajax请求可能正在尝试完成以下任何事情:
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 Action”的概念,而是取消区别并坚持直接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
之类的类存在是因为他们希望一些开发人员使用请求检测方法。但是在对两者进行了相当多的实验之后,我发现很多更容易推理,因此更容易设计/编码。