Reporting errors from Ajax invoked PartialView methods in MVC
Controller action:
public ActionResult Foo(){ // Obviously DoSomething could throw but if we start // trying and catching on every single thing that could throw // our controller actions will resemble some horrible plumbing code more // than what they normally should resemble: a.k.a being slim and focus on // what really matters which is fetch a model and pass to the view // Here you could return any type of view you like: JSON, HTML, XML, CSV, PDF, ... var model = DoSomething(); return PartialView(model);}
Then we define a Global error handler for our application:
protected void Application_Error(object sender, EventArgs e){ var exception = Server.GetLastError(); var httpException = exception as HttpException; Response.Clear(); Server.ClearError(); if (new HttpRequestWrapper(Request).IsAjaxRequest()) { // Some error occurred during the execution of the request and // the client made an AJAX request so let's return the error // message as a JSON object but we could really return any JSON structure // we would like here Response.StatusCode = 500; Response.ContentType = "application/json"; Response.Write(new JavaScriptSerializer().Serialize(new { errorMessage = exception.Message })); return; } // Here we do standard error handling as shown in this answer: // http://stackoverflow.com/q/5229581/29407 var routeData = new RouteData(); routeData.Values["controller"] = "Errors"; routeData.Values["action"] = "General"; routeData.Values["exception"] = exception; Response.StatusCode = 500; if (httpException != null) { Response.StatusCode = httpException.GetHttpCode(); switch (Response.StatusCode) { case 404: routeData.Values["action"] = "Http404"; break; case 500: routeData.Values["action"] = "Http500"; break; } } IController errorsController = new ErrorsController(); var rc = new RequestContext(new HttpContextWrapper(Context), routeData); errorsController.Execute(rc);}
Here's how the ErrorsController used in the global error handler could look like. Probably we could define some custom views for the 404 and 500 actions:
public class ErrorsController : Controller{ public ActionResult Http404() { return Content("Oops 404"); } public ActionResult Http500() { return Content("500, something very bad happened"); }}
Then we could subscribe for a global error handler for all AJAX errors so that we don't have to repeat this error handling code for all AJAX requests but if we wanted we could repeat it:
$('body').ajaxError(function (evt, jqXHR) { var error = $.parseJSON(jqXHR.responseText); alert('An error occured: ' + error.errorMessage);});
And finally we fire an AJAX request to the controller action that we hope will return an HTML partial in this case:
$.ajax({ url: 'whatever/trevor', success: function (html) { $container.html(html); }});
Create an overriden version of HandleErrorAttribute (JsonHandleErrorAttribute ?) and add [JsonHandleError] on your json action.
Have a look at AjaxAuthorizeAttribute in asp.net mvc [handleerror] [authorize] with JsonResult?