7

Jeśli błędy ładowania normalnego strony mogę zgłosić szczegóły wyjątku do użytkownika za pośrednictwem widoku Error i modelu HandleErrorInfo.Zgłaszanie błędów z Ajax wywołanych metod PartialView w MVC

Jeśli ajax wezwanie spodziewa się Json błędy rezultacie mogę jawnie obsługi błędu i przekazać dane do klienta:

public JsonResult Whatever() 
{ 
    try 
    { 
     DoSomething(); 
     return Json(new { status = "OK" }); 
    } 
    catch (Exception e) 
    { 
     return Json(new { status = "Error", message = e.Message }); 
    } 
} 

Więc mój problem, nie widzę żadnych sposób Szczegóły Raport o błędach od wywołania Ajax do akcji zwracającej częściowy widok.

$.ajax({ 
    url: 'whatever/trevor', 
    error: function (jqXHR, status, error) { 
     alert('An error occured: ' + error); 
    }, 
    success: function (html) { 
     $container.html(html); 
    } 
}); 

Spowoduje to zgłoszenie tylko kodu błędu HTTP (np. Błąd serwera wewnętrznego), który nie jest pomocny dla klienta. Czy istnieje jakiś sprytny trik do przekazania albo udanego wyniku PartialView (html) lub komunikatu o błędzie?

Jawna ocena html z ViewResult i zwrócenie go jako części obiektu Json wraz ze statusem wydaje się zbyt śmierdząca. Czy istnieje ustalony wzorzec postępowania w tym scenariuszu?

Odpowiedz

14

Controller działanie:

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

Następnie definiujemy globalnej obsługi błędów dla naszej aplikacji:

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

Oto jak ErrorsController stosowane w globalnej obsługi błędów mogłoby wyglądać. Prawdopodobnie możemy zdefiniować kilka widoków niestandardowych dla działań 404 i 500:

public class ErrorsController : Controller 
{ 
    public ActionResult Http404() 
    { 
     return Content("Oops 404"); 
    } 

    public ActionResult Http500() 
    { 
     return Content("500, something very bad happened"); 
    } 
} 

Wtedy moglibyśmy zapisać się na global error handler dla wszystkich błędów AJAX, dzięki czemu nie musimy powtórzyć ten kod obsługi błędów dla wszystkich żądań AJAX ale jeśli chcemy możemy to powtórzyć:

$('body').ajaxError(function (evt, jqXHR) { 
    var error = $.parseJSON(jqXHR.responseText); 
    alert('An error occured: ' + error.errorMessage); 
}); 

I wreszcie ogień żądania AJAX do działania kontrolera, które mamy nadzieję, że zwróci częściowy HTML w tym przypadku:

$.ajax({ 
    url: 'whatever/trevor', 
    success: function (html) { 
     $container.html(html); 
    } 
}); 
+1

Darin swoją znajomość MVC zadziwia mnie ponownie. Nie w pełni rozumiem kilka punktów tutaj, ale doszedłem do wniosku, że mogę osiągnąć coś podobnego nieco prostszego z filtrem ajaxowym zarejestrowanym w filtrach globalnych. Wydaje się, że działa dobrze. Dziękuję Ci. – fearofawhackplanet

+0

Tylko uwaga, jeśli używasz powyższego kodu do pułapki 404 i pokazywania niestandardowej strony, prawdopodobnie chcesz dodać Response.TrySkipIisCustomErrors = true (chyba tylko w .NET 3.5 wierzę) –

+0

Działa jak urok, awesome – Dilip

Powiązane problemy