代码之家  ›  专栏  ›  技术社区  ›  Kirschstein

使用筛选器执行其他操作?

  •  2
  • Kirschstein  · 技术社区  · 15 年前

    我想避免有很多 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请求量加倍似乎有点毫无意义。

    是否有不同的方法将请求路由到不同的操作?或者我所做的是不可取的,我应该寻找一种更好的方法来做事情?

    干杯

    2 回复  |  直到 15 年前
        1
  •  1
  •   Aaronaught    15 年前

    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操作选择器在这些方法之间进行选择遵循 “优雅的退化” 已被(至少在国际海事组织)取代 渐进增强 .

    这就是为什么,尽管我喜欢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。控制者的动作简短而甜美,正是他们应该做的。

    这不是唯一的方法。显然,像 接受属性 存在是因为他们希望一些开发人员使用请求检测方法。但在对两者进行了相当多的试验之后,我发现 许多的 更容易推理,因此更容易正确设计/编码。

        2
  •  2
  •   takepara    15 年前

    mvcfutures中的acceptyjaxattribute如何?