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.
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;
},
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With