Как условно направить действие, если запрос происходит из вызова AJAX? - PullRequest
0 голосов
/ 20 февраля 2012

Используя маршрутизацию APS.NET, как условно направить отдельные действия в зависимости от того, был ли запрос инициирован как вызов AJAX?

Например, на контроллере у меня может быть два действия:

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

и

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

Мне бы хотелось, чтобы оба действия имели один и тот же URL, но ListJSON () должен вызываться, если запрос возник как вызов AJAX.

Ответы [ 2 ]

2 голосов
/ 20 февраля 2012

Зачем использовать 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
                 };
             }
         }
     }
}

Вы также можете зарегистрировать этот фильтр действий какФильтр глобального действия, чтобы избежать необходимости помещать его на каждый контроллер и действие, которое требует его.


ОБНОВЛЕНИЕ:

Как объяснено в разделе комментариев, кажется, что 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 }
        )
    );
}
0 голосов
/ 20 февраля 2012

Оказывается, вы можете легко определить свои собственные ограничения маршрута, внедрив 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. Но я не проверил их значительно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...