Using an MVC Action Filter to catch redirects in Ajax requests and return a JsonResult
In my ASP.NET MVC 3 application, I have some action methods that can be invoked with Ajax and non-Ajax requests. The action methods may return a RedirectResult and I want the 开发者_开发百科target URL to be loaded in the browser - even for Ajax requests.
My current solution is for the action method to call IsAjaxRequest itself. If false, it returns a RedirectResult. If true, it returns a JsonResult containing the target URL, and I have script in the browser to read this and set window.location accordingly.
I was hoping to declutter the action methods and handle this in a filter. My problem is that the target URL (filterContext.HttpContext.Response.RedirectLocation) is null in the filter event handlers other than OnResultExecuted, and setting filterContext.Result in that handler (and changing response.StatusCode) doesn't succeed in issuing JSON in the response.
If I use one of the other handlers, such as OnActionExecuted, I can change the response to issue JSON, but cannot get hold of the target URL.
A 2-step process does not work either - if I change the result to a JsonResult in OnActionExecuted, the RedirectLocation is null in OnResultExecuted.
Can anyone recreate this problem or recommend a better solution? Thanks.
PS here is the code from OnResultExecuted:
if ((filterContext.Result is RedirectToRouteResult ||
filterContext.Result is RedirectResult) &&
filterContext.HttpContext.Request.IsAjaxRequest())
{
string url = filterContext.HttpContext.Response.RedirectLocation;
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
filterContext.HttpContext.Response.RedirectLocation = "";
filterContext.Result = new JsonResult
{
Data = new { Redirect = url },
ContentEncoding = System.Text.Encoding.UTF8,
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
Here's an example of how you could proceed:
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
string url = "/";
var redirectResult = filterContext.Result as RedirectResult;
if (filterContext.Result is RedirectResult)
{
// It was a RedirectResult => we need to calculate the url
var result = filterContext.Result as RedirectResult;
url = UrlHelper.GenerateContentUrl(result.Url, filterContext.HttpContext);
}
else if (filterContext.Result is RedirectToRouteResult)
{
// It was a RedirectToRouteResult => we need to calculate
// the target url
var result = filterContext.Result as RedirectToRouteResult;
url = UrlHelper.GenerateUrl(result.RouteName, null, null, result.RouteValues, RouteTable.Routes, filterContext.RequestContext, false);
}
filterContext.Result = new JsonResult
{
Data = new { Redirect = url },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
// TODO: It is not an AJAX request => do whatever you were doing
}
}
精彩评论