0
votes

I have a Login page which uses an Ajax Form. Within the Action called, I want to redirect to a different Controller / Action, based on some criteria. For now, I am not worrying about that but just trying to get the Redirect to work.

It seems to be complicated by an ActionFilterAttribute:

public class AjaxAwareRedirectAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var result = filterContext.Result as RedirectResult;
        if (result != null && filterContext.HttpContext.Request.IsAjaxRequest())
        {
            string destinationUrl = UrlHelper.GenerateContentUrl(result.Url, filterContext.HttpContext);
            filterContext.Result = new JavaScriptResult()
            {
                Script = string.Format("window.location = '{0}';", destinationUrl)
            };
        }
    }
}

This fires after the Login page controller action calls

return RedirectToAction("Index", "TwoFactorAuthentication");

The redirect is ignored and the Login page is redisplayed.

The AjaxAwareRedirectAttribute attribute is used in many places throughout the site, so I need to be careful what (if anything) I do to it.

If I use a simple

return Redirect("/en/authentication");

Then that seems to work fine. However, I would also like to pass model data like this

return RedirectToAction("Index", "TwoFactorAuthentication", member);

I'm now not sure if I'm close and on the right track, or completely wrong!

This is an Umbraco 7 project, if that has any bearing on it.

Edit:

Do I need to detect / process the redirect on the client side instead?

This is the Ajax form

@using (Ajax.BeginForm("Login", "LoginSignup", null, options, null))

These are the options

var options = new AjaxOptions
{
    HttpMethod = "POST",
    OnFailure = "ShowError",
    OnSuccess = "ShowSuccess",
    UpdateTargetId = "target1",
    InsertionMode = InsertionMode.Replace
};

And the associated script

<script>
    function ShowError(response) {
        $("#feedback").show();
        $("#signupfeedback").show();
        $("#status").html("@Umbraco.Field("#Login.ScriptErrorPostingForm")");
    }

    function ShowSuccess(response, textStatus, xhr) {
        if (xhr.responseText.indexOf('window') == -1) {
            $("#feedback").show();
            $("#signupfeedback").show();
            $(".validation-summary-errors").hide();
        }
    }

    function ShowExternalLoginError() {
        $("#status").removeClass();
        $("#status").addClass("b_noteList");
        $("#status").html("@Umbraco.Field("#Login.ScriptErrorOccurred")");
    }

</script>
1
How are you handling client side? Ajax and redirects can be tricky.Kevin B Burns
@KevinBBurns - I have updated my question with the relevant Ajax details.GordonS

1 Answers

0
votes

The problem here is within AjaxAwareRedirectAttribute attribute.

var result = filterContext.Result as RedirectResult;

In the line above you expect to receive RedirectResult. However, whenever you call RedirectToAction method, the output result becomes of type RedirectToRouteResult.

That's why it doesn't work.

You can either adjust AjaxAwareRedirectAttribute or continue using simple Redirect method and pass argument as query string parameters. (in the end, that's the only way to pass parameters via redirect).

Here is a simplified solution which you can use if you still want to change the attribute: (please, note that edge cases are not covered and the code itself should be refactored a bit)

public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        string destination = null;
        if(filterContext.Result is RedirectResult redirect)
        {
            destination = redirect.Url;
        }
        else if (filterContext.Result is RedirectToRouteResult routeRedirect)
        {
            var action = (string)routeRedirect.RouteValues["Action"];
            var controller = (string)routeRedirect.RouteValues["Controller"];

            var helper = new UrlHelper(filterContext.RequestContext);
            destination = helper.Action(action, controller, routeRedirect.RouteValues);
        }

        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            string destinationUrl = UrlHelper.GenerateContentUrl(destination, filterContext.HttpContext);
            filterContext.Result = new JavaScriptResult()
            {
                Script = string.Format("window.location = '{0}';", destinationUrl)
            };
        }
    }

If you don't want to touch the common code:

var url = Url.Action("Action", "Controller" , new { data = "test" });
return Redirect(url);