【问题标题】:How do you conditionally route to an action if the request originates from an AJAX call?如果请求来自 AJAX 调用,您如何有条件地路由到某个操作?
【发布时间】:2012-02-20 13:03:46
【问题描述】:

使用 APS.NET 路由,如何根据请求是否源自 AJAX 调用,有条件地路由到单独的操作?

例如在控制器上我可能有两个动作:

public ActionResult List() { return View(); }

public ActionResult ListJSON() { return Content(...); }

我希望两个操作具有相同的 URL,但如果请求源自 AJAX 调用,则应该调用 ListJSON()。

【问题讨论】:

    标签: ajax asp.net-mvc url-routing


    【解决方案1】:

    为什么在代码相同的情况下使用 2 个单独的操作?不同的是查看结果。

    怎么样:

    public ActionResult List()
    {
        var model = ...
        if (Request.IsAjaxRequest())
        {
            return View(model);
        }
        return Json(model);
    }
    

    显然,如果您必须在每个控制器操作中都这样做,这将很快成为一场彻头彻尾的噩梦。

    因此您可以将此逻辑外部化到自定义操作过滤器中:

    [MyFilter]
    public ActionResult List()
    {
        var model = ...
        return View(model);
    }
    

    您可以像这样定义MyFilterAttribute

    public class MyFilterAttribute: ActionFilterAttribute
    {
         public override void OnResultExecuted(ResultExecutedContext filterContext)
         {
             if (filterContext.HttpContext.Request.IsAjaxRequest())   
             {
                 var result = filterContext.Result as ViewResultBase;
                 if (result != null)
                 {
                     filterContext.Result = new JsonResult
                     {
                         Data = result.Model,
                         JsonRequestBehavior = JsonRequestBehavior.AllowGet
                     };
                 }
             }
         }
    }
    

    您还可以将此操作过滤器注册为全局操作过滤器,以避免将其放在需要它的每个控制器和操作上。


    更新:

    如 cmets 部分所述,OP 似乎需要 2 个不同的操作。为此,您可以使用自定义路由:

    public class MyRoute : Route
    {
        public MyRoute(string url, object defaults) :
            base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
        {
        }
    
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            var rd = base.GetRouteData(httpContext);
            if (rd == null)
            {
                return null;
            }
    
            if (httpContext.Request.IsAjaxRequest())
            {
                rd.Values["action"] = rd.GetRequiredString("action") + "json";
            }
    
            return rd;
        }
    }
    

    将在Application_Start注册:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
        routes.Add(
            "Default",
            new MyRoute(
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            )
        );
    }
    

    【讨论】:

    • 代码可能不一样。执行的查询和所需的数据可能会有很大差异。从可测试性的角度来看,有两个方法会更简洁,但是根据请求在它们之间进行路由。
    • 这是一个聪明的主意。但是,由于您正在操纵“action”值,我想知道它会如何影响出站 URL 的生成。
    【解决方案2】:

    事实证明,您可以通过实现IRouteConstraint 轻松定义自己的路由约束。

    类似这样的:

    public class AjaxRouteConstraint : IRouteConstraint {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
            return httpContext.Request.IsAjaxRequest();
        }
    }
    

    然后简单地在路由上使用这个约束。诀窍是有这个约束的路由必须在没有约束的路由之前,否则ajax路由永远不会被调用(not-ajax路由会一直匹配)。

    在生成 URL 时,这样做可能会产生一些后果。但我没有对这些进行过显着测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-16
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-14
      相关资源
      最近更新 更多