2011-01-16 19 views
106

Wie gehe ich mit Ausnahmen um, die in einem Controller ausgelöst werden, wenn jquery ajax eine Aktion aufruft?ASP.NET MVC Ajax Fehlerbehandlung

Zum Beispiel möchte ich einen globalen JavaScript-Code, der auf jeder Art von Server-Ausnahme während eines Ajax-Aufrufs ausgeführt wird, die die Ausnahmebedingungsnachricht im Debug-Modus oder nur eine normale Fehlermeldung anzeigt.

Auf der Client-Seite werde ich eine Funktion auf den Ajax-Fehler aufrufen.

Auf der Serverseite, muss ich einen benutzerdefinierten Actionfilter schreiben?

$.ajax({ 
    url: '/foo', 
    success: function(result) { 
     alert('yeap'); 
    }, 
    error: function(XMLHttpRequest, textStatus, errorThrown) { 
     alert('oops, something bad happened'); 
    } 
}); 

und einen globalen Fehlerhandler registrieren Sie $.ajaxSetup() Methode verwenden könnte:

+8

Siehe [Beckelmans Beitrag] (http://beckelman.net/post/2010/03/18/Handling-Errors-During-Ajax-Calls-With-ASPNET-MVC.aspx) für ein gutes Beispiel. Darins Antwort auf diesen Beitrag ist gut, aber nicht den richtigen Statuscode für einen Fehler. – Dan

+6

Leider ist dieser Link jetzt defekt –

+1

Hier ist der Link auf Wayback-Maschine: https://web.archive.org/web/20111011105139/http://beckelman.net/post/2010/03/18/Handling-Errors- Während-Ajax-Anrufe-Mit-ASPNET-MVC.aspx – BruceHill

Antwort

151

Wenn der Server eine Statuscode anders als 200 sendet, wird die Fehler-Callback ausgeführt

$.ajaxSetup({ 
    error: function(XMLHttpRequest, textStatus, errorThrown) { 
     alert('oops, something bad happened'); 
    } 
}); 

Ein weiterer Weg ist es, JSON zu verwenden. So könnten Sie eine benutzerdefinierte Aktion Filter auf dem Server schreiben, die Ausnahme abfängt und verwandelt sie in JSON-Antwort:

public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter 
{ 
    public void OnException(ExceptionContext filterContext) 
    { 
     filterContext.ExceptionHandled = true; 
     filterContext.Result = new JsonResult 
     { 
      Data = new { success = false, error = filterContext.Exception.ToString() }, 
      JsonRequestBehavior = JsonRequestBehavior.AllowGet 
     }; 
    } 
} 

und dann schmücken Sie Ihre Controller-Aktion mit diesem Attribut:

[MyErrorHandler] 
public ActionResult Foo(string id) 
{ 
    if (string.IsNullOrEmpty(id)) 
    { 
     throw new Exception("oh no"); 
    } 
    return Json(new { success = true }); 
} 

und es schließlich aufrufen:

$.getJSON('/home/foo', { id: null }, function (result) { 
    if (!result.success) { 
     alert(result.error); 
    } else { 
     // handle the success 
    } 
}); 
+1

Danke dafür, Letzteres war, was ich gesucht habe. Also gibt es für die asp.net mvc-Ausnahme eine bestimmte Art, die ich es werfen muss, so dass es von der jquery-Fehlerbehandlungsroutine abgefangen werden kann? –

+1

@Lol Coder, egal wie Sie eine Ausnahme in der Controller-Aktion werfen wird der Server 500 Statuscode zurückgeben und der 'Fehler' Callback wird ausgeführt. –

+0

Danke, perfekt, genau das, was ich gesucht habe. –

0

Für Fehler von ajax-Aufrufen auf der Client-Seite Umgang mit einer Funktion zum Aufruf error Option des ajax zuweisen.

Um global eine Standardeinstellung festzulegen, können Sie die hier beschriebene Funktion verwenden: http://api.jquery.com/jQuery.ajaxSetup.

+0

Eine Antwort, die ich vor mehr als 4 Jahren gab, wird plötzlich abgelehnt. Möchte jemand einen Grund angeben? –

+1

Setzen Sie sich mit SOF in Verbindung und fragen Sie ihren DBA, abzufragen, wer die Ablehnung abgegeben hat. Als nächstes melden Sie diese Person, damit sie erklären können. Nicht jeder kann einen Grund dafür angeben. – JoshYates1980

69

Nach googeln schreibe ich eine einfache Ausnahmegabe basierend auf MVC Aktion Filter:

public class HandleExceptionAttribute : HandleErrorAttribute 
{ 
    public override void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null) 
     { 
      filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 
      filterContext.Result = new JsonResult 
      { 
       JsonRequestBehavior = JsonRequestBehavior.AllowGet, 
       Data = new 
       { 
        filterContext.Exception.Message, 
        filterContext.Exception.StackTrace 
       } 
      }; 
      filterContext.ExceptionHandled = true; 
     } 
     else 
     { 
      base.OnException(filterContext); 
     } 
    } 
} 

und schreiben in global.ascx:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
     filters.Add(new HandleExceptionAttribute()); 
} 

und dann schreiben Sie dieses Skript auf dem Layout oder Master-Seite :

<script type="text/javascript"> 
     $(document).ajaxError(function (e, jqxhr, settings, exception) { 
         e.stopPropagation(); 
         if (jqxhr != null) 
          alert(jqxhr.responseText); 
        }); 
</script> 

Schließlich sollten Sie benutzerdefinierte Fehler aktivieren. und dann genießen Sie es :)

+0

Ich kann den Fehler in Firebug sehen, aber es wird nicht auf Error-Seite umgeleitet. – user2067567

+1

Danke dafür! sollte als die Antwort IMO als seine Filterung auf Ajax-Anfragen markiert werden und erbt die richtige Klasse und nicht, was das HandleErrorAttribute erbt –

+2

Wunderbare Antwort! : D –

2

Ich habe eine schnelle Lösung, weil ich knapp war und es hat funktioniert. Obwohl ich denke, dass die bessere Option ein Ausnahmefilter ist, kann meine Lösung vielleicht helfen, falls eine einfache Lösung benötigt wird.

Ich habe folgendes getan.In der Controller-Methode zurück ich ein JsonResult mit einer Eigenschaft „Erfolg“ in den Daten:

[HttpPut] 
    public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave) 
    { 
     if (!ModelState.IsValid) 
     { 
      return new JsonResult 
      { 
       Data = new { ErrorMessage = "Model is not valid", Success = false }, 
       ContentEncoding = System.Text.Encoding.UTF8, 
       JsonRequestBehavior = JsonRequestBehavior.DenyGet 
      }; 
     } 
     try 
     { 
      MyDbContext db = new MyDbContext(); 

      db.Entry(employeToSave).State = EntityState.Modified; 
      db.SaveChanges(); 

      DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"]; 

      if (employeToSave.Id == user.Id) 
      { 
       user.Company = employeToSave.Company; 
       user.Language = employeToSave.Language; 
       user.Money = employeToSave.Money; 
       user.CostCenter = employeToSave.CostCenter; 

       Session["EmployeLoggin"] = user; 
      } 
     } 
     catch (Exception ex) 
     { 
      return new JsonResult 
      { 
       Data = new { ErrorMessage = ex.Message, Success = false }, 
       ContentEncoding = System.Text.Encoding.UTF8, 
       JsonRequestBehavior = JsonRequestBehavior.DenyGet 
      }; 
     } 

     return new JsonResult() { Data = new { Success = true }, }; 
    } 

Später in dem Ajax-Aufruf Ich habe gerade für diese Eigenschaft gefragt, ob ich eine Ausnahme hatte:

$.ajax({ 
    url: 'UpdateEmployeeConfig', 
    type: 'PUT', 
    data: JSON.stringify(EmployeConfig), 
    contentType: "application/json;charset=utf-8", 
    success: function (data) { 
     if (data.Success) { 
      //This is for the example. Please do something prettier for the user, :) 
      alert('All was really ok');           
     } 
     else { 
      alert('Oups.. we had errors: ' + data.ErrorMessage); 
     } 
    }, 
    error: function (request, status, error) { 
     alert('oh, errors here. The call to the server is not working.') 
    } 
}); 

Hoffe, das hilft. Glücklicher Code! : P

9

Leider sind keine der Antworten gut für mich. Überraschenderweise ist die Lösung viel einfacher. Rückgabe vom Controller:

return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase); 

Und behandeln Sie es als Standard-HTTP-Fehler auf dem Client, wie Sie möchten.

+0

Was ist das "e" in Ihrem Code-Snippet? –

+0

@Will Huang: der Name der Ausnahme-Instanz – schmendrick

+0

Ich muss das erste Argument auf "Int" werfen. Wenn ich dies tue, wird das Ergebnis auch an den 'ajax'' success'-Handler und nicht den 'error'-Handler übergeben. Ist das das erwartete Verhalten? –

4

In Übereinstimmung mit Alehos Antwort hier ist ein komplettes Beispiel. Es funktioniert wie ein Zauber und ist super einfach.

Controller-Code

[HttpGet] 
public async Task<ActionResult> ChildItems() 
{ 
    var client = TranslationDataHttpClient.GetClient(); 
    HttpResponseMessage response = await client.GetAsync("childItems); 

    if (response.IsSuccessStatusCode) 
     { 
      string content = response.Content.ReadAsStringAsync().Result; 
      List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content); 
      return Json(content, JsonRequestBehavior.AllowGet); 
     } 
     else 
     { 
      return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase); 
     } 
    } 
} 

Javascript-Code in der Ansicht

var url = '@Html.Raw(@Url.Action("ChildItems", "WorkflowItemModal")'; 

$.ajax({ 
    type: "GET", 
    dataType: "json", 
    url: url, 
    contentType: "application/json; charset=utf-8", 
    success: function (data) { 
     // Do something with the returned data 
    }, 
    error: function (xhr, status, error) { 
     // Handle the error. 
    } 
}); 

Hope this jemand anderes hilft!