如果请求来自AJAX调用,您如何有条件地路由到操作?

如果请求来自AJAX调用,您如何有条件地路由到操作?,ajax,asp.net-mvc,url-routing,Ajax,Asp.net Mvc,Url Routing,使用APS.NET路由,如何根据请求是否作为AJAX调用发起,有条件地路由到单独的操作 例如,在控制器上,我可能有两个操作: public ActionResult List() { return View(); } 及 我希望两个操作具有相同的URL,但是如果请求是作为AJAX调用发出的,则应该调用ListJSON()?不同的是视图结果 那么: public ActionResult List() { var model = ... if (Request.IsAjaxReq

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

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

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


我希望两个操作具有相同的URL,但是如果请求是作为AJAX调用发出的,则应该调用ListJSON()?不同的是视图结果

那么:

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
                 };
             }
         }
     }
}
您还可以将此操作筛选器注册为全局操作筛选器,以避免将其放在每个控制器和需要它的操作上


更新:

如评论部分所述,OP似乎需要两种不同的操作。为此,您可以使用自定义路线:

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;
    }
}
将在
应用程序\u 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 }
        )
    );
}

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

大概是这样的:

public class AjaxRouteConstraint : IRouteConstraint {
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
        return httpContext.Request.IsAjaxRequest();
    }
}
然后只需在管线上使用此约束。诀窍在于,具有此约束的路由必须位于不具有此约束的路由之前,否则将永远不会调用ajax路由(非ajax路由将始终匹配)


当涉及到URL生成时,这样做可能会产生一些后果。但是我没有对它们进行显著的测试。

代码可能不一样。执行的查询和所需的数据可能会有很大差异。从可测试性的角度来看,有两个方法要干净得多,但是根据请求在它们之间进行路由。这是一个聪明的想法。然而,由于您正在操作“action”值,我想知道它会如何影响出站URL的生成。
public class AjaxRouteConstraint : IRouteConstraint {
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
        return httpContext.Request.IsAjaxRequest();
    }
}