Using an MVC Action Filter to catch redirects in A

2019-02-02 20:06发布

问题:

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
    };
}

回答1:

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
    }
}