Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect on success and show error on failure

I have implemented a controller to create new users. When it creates the user successfully it redirects to Index().

What I want is to get redirected when all is OK, but stay in the current page and see the error when something failed.

I'm using jQuery ajax with MVC.

My controller looks like this:

[Authorize]
public ActionResult CreateUser(string username)
{
    try
    {
        //here the logic to create the user
    }   
    catch (Exception ex)
    {
        string error = string.Format("Error creating user: {0}", ex.Message);
        Response.StatusCode = 500;
        Response.Write(error);    
    }
    return RedirectToAction("Index");
}

The form submit is intercepted with jQuery, and then the call is made with ajax:

$("#new-user-form").submit(function() {
    var form = $(this);
    $.ajax({
    type: "GET",
        url: form.attr('action'),
        data: form.serialize(),
        success: function(data, textStatus, xhr) {
            //At this point I would like to redirect
        },
        error: function(xhr, textStatus, errorThrown) {
            $(".error-summary").html(xhr.responseText);
        }
    });

    //cancel the event
    return false;
});

It works fine when an error occurs, but I don't know how to implement the success case.

I'm opened to other alternatives.

like image 310
Daniel Peñalba Avatar asked Dec 20 '10 19:12

Daniel Peñalba


2 Answers

If you are going to redirect in the success action why are you using AJAX? The purpose of AJAX is to refresh only parts of a site without reloading the whole page. If in the success action you are going to redirect that totally defeats all the purpose and benefits you get from AJAX. But because you asked here's what you could do:

[Authorize]
public ActionResult CreateUser(string username)
{
    ...
    if (Request.IsAjaxRequest())
    {
        return Json(new { redirectToUrl = Url.Action("Index") });
    }
    return RedirectToAction("Index");
}

And then:

success: function(data, textStatus, xhr) {
    window.location.href = data.redirectToUrl;
},
like image 81
Darin Dimitrov Avatar answered Oct 11 '22 08:10

Darin Dimitrov


Here is an alternative answer which uses pure MVC classes and you don't have to hardcode any script or use jQuery. First, I found the validators of MVC 2 work fine in success, failure and confirm cases as long as you remember:

1) Include necessary MVC scripts (three in total plus EnableClientSideValidation call - see MSDN).

2) Put MetadataClassAttribute and RequiredAttribtues on your model/data entities. You don't have to create separate metadata classes and make your model partial (I find that pants) just reference the same model class in the attribute.

3) Solve the AJAX redirect issue by returning JavaScript as already suggested (but in a jQuery orientated way)...

I only suffered strange behaviour during validation when it already failed to redirect from the list page to a details/edit page. The error messages would appear for a few seconds then disappear! Of course it was confused because the shell of the page was the first list page and the inner contents from the edit page. So the root cause of the problem was the out-the-box MVC 2 toolkit failing to redirect properly from the first page, not that the validators were not working properly on the second page.

I found the same solution here:

http://craftycodeblog.com/2010/05/15/asp-net-mvc-ajax-redirect/ ...which I expanded into an extension method and class in VB.NET:

    ''' <summary>
    ''' MVC extension methods.
    ''' </summary>
    Public Module MvcExtensions

        ''' <summary>
        ''' Returns an <see cref="AjaxAwareRedirectResult"/> for the specified action
        ''' and optional controller name.
        ''' </summary>
        <Extension()> _
        Public Function AjaxAwareRedirectToAction(controller As Controller, _
                                         actionName As String, _
                                         Optional controllerName As String = Nothing) _
                                     As RedirectResult

            ' Get target URL
            Dim url = controller.Url.Action(actionName, controllerName)

            ' Return AJAX aware redirect result
            Return New AjaxAwareRedirectResult(url)

        End Function

   End Module

    ''' <summary>
    ''' <see cref="RedirectResult"/> which works with MVC 2 AJAX.
    ''' </summary>
    ''' <remarks>
    ''' Normal redirects do not work with AJAX partial updates in MVC (HTTP 302 status).
    ''' With MVC 2 AJAX it is necessary to return JavaScript to change the browser location.
    ''' </remarks>
    Public Class AjaxAwareRedirectResult
        Inherits RedirectResult

        ''' <summary>
        ''' Creates an instance which redirects to the specified URL using
        ''' a response containing either AJAX JavaScript or classic HTTPS 302 status.
        ''' </summary>
        ''' <param name="url">Target URL.</param>
        Sub New(url As String)
            MyBase.New(url)
        End Sub

        ''' <summary>
        ''' Generates the response.
        ''' </summary>
        Public Overrides Sub ExecuteResult(ByVal context As ControllerContext)

            ' Check if AJAX was used for request
            If context.RequestContext.HttpContext.Request.IsAjaxRequest Then

                ' Perform JavaScript redirect when AJAX is used
                Dim destinationUrl As String = UrlHelper.GenerateContentUrl(Url, context.HttpContext)
                Dim result As JavaScriptResult = New JavaScriptResult With {
                        .Script = ("window.location='" + destinationUrl + "';")}
                result.ExecuteResult(context)

            Else

                ' Perform classic HTTP 302 status redirect
                MyBase.ExecuteResult(context)

            End If

        End Sub

    End Class

So then you have two options. You can follow the typical MVC pattern of calling AjaxAwareRedirectToAction(aciton, [controller]) for MVC targets, or return a new instance of an AjaxAwareRedirectResult(url) when you have a specific URL target in mind (i.e. external site).

I was really surprised that Microsoft didn't get AJAX redirects sorted in the first MVC 2 RTM. I have to use MVC 2 on my current project which is why I have to suffer this limitation, but also have some newer MVC solutions which I see are leaning more towards jQuery for validation. I will find out soon if they fixed it.

like image 44
Tony Wall Avatar answered Oct 11 '22 08:10

Tony Wall