2011-01-16 20 views
106

Come si gestiscono le eccezioni generate in un controller quando jquery ajax chiama un'azione?ASP.NET MVC Ajax Gestione degli errori

Ad esempio, desidero un codice javascript globale che venga eseguito su qualsiasi tipo di eccezione del server durante una chiamata ajax che visualizza il messaggio di eccezione se in modalità di debug o solo un normale messaggio di errore.

Sul lato client, chiamerò una funzione sull'errore Ajax.

Sul lato server, Devo scrivere un actionfilter personalizzato?

+8

Vedere [post di beckelmans] (http://beckelman.net/post/2010/03/18/Handling-Errors-During-Ajax-Calls-With-ASPNET-MVC.aspx) per un buon esempio. La risposta di Darin a questo post è buona, ma non impostare il codice di stato corretto per un errore. – Dan

+6

Purtroppo il link è ora rotto –

+1

Ecco il link sulla macchina del wayback: https://web.archive.org/web/20111011105139/http://beckelman.net/post/2010/03/18/Handling-Errors- Durante-Ajax-Calls-With-ASPNET-MVC.aspx – BruceHill

risposta

151

Se il server invia un codice di stato diverso rispetto a 200, viene eseguita la richiamata di errore:

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

e di registrare un gestore errori globale è possibile utilizzare il metodo $.ajaxSetup():

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

altro il modo è usare JSON. Così si potrebbe scrivere un filtro di un'azione personalizzata sul server che cattura eccezione e li trasforma in JSON risposta:

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

e poi decorare la vostra azione di controllo con questo attributo:

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

e, infine, invocarlo:

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

Grazie per questo, quest'ultimo era quello che stavo cercando. Quindi, per l'eccezione asp.net mvc, c'è un modo specifico che ho bisogno di lanciarlo in modo che possa essere catturato dal gestore degli errori jquery? –

+1

Codificatore @Lol, indipendentemente da come si genera un'eccezione all'interno dell'azione del controller, il server restituirà un codice di stato di 500 e verrà eseguita la richiamata di 'error'. –

+0

Grazie, perfetto, proprio quello che stavo cercando. –

0

per la gestione degli errori dalle chiamate Ajax sul lato client, si assegna una funzione per l'opzione error della chiamata AJAX.

Per impostare un valore globale a livello globale, è possibile utilizzare la funzione qui descritta: http://api.jquery.com/jQuery.ajaxSetup.

+0

Una risposta che ho dato oltre 4 anni fa improvvisamente ottiene un voto negativo? Qualcuno si preoccupa di dare una ragione perché? –

+1

Contatta SOF e chiedi al loro DBA di chiedere chi ha votato. Quindi, invia un messaggio all'individuo in modo che possano spiegare. Non tutti possono dare una ragione per cui. – JoshYates1980

69

Dopo googling scrivo una semplice consegna delle eccezioni in base a MVC Operazione filtro:

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

e scrivere in global.ascx:

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

e poi scrivere questo script nella pagina layout o master :

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

Infine, è necessario attivare l'errore personalizzato. e poi divertitevi :)

+0

Posso vedere l'errore in Firebug ma non sta reindirizzando alla pagina di errore.? – user2067567

+1

Grazie per questo! dovrebbe essere contrassegnato come la risposta IMO come il suo filtraggio su richieste Ajax e eredita la classe corretta piuttosto che il HandleErrorAttribute eredita la risposta meravigliosa –

+2

! : D –

2

Ho fatto una soluzione rapida perché avevo poco tempo e funzionava bene. Anche se penso che l'opzione migliore sia utilizzare un filtro di eccezione, forse la mia soluzione può aiutare nel caso in cui sia necessaria una soluzione semplice.

Ho fatto quanto segue.Nel metodo di controllo sono tornato un JsonResult con una proprietà "Success" all'interno dei dati:

[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 }, }; 
    } 

Nel corso della chiamata AJAX ho solo chiesto per questa proprietà per sapere se avevo un'eccezione:

$.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.') 
    } 
}); 

Spero che questo aiuti. Buon codice! : P

9

Sfortunatamente, nessuna delle risposte è buona per me. Sorprendentemente la soluzione è molto più semplice. Ritorno dal controller:

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

E gestirlo come errore HTTP standard sul client come desiderato.

+0

Che cosa significa "e" nel tuo snippet di codice? –

+0

@Will Huang: il nome dell'istanza di eccezione – schmendrick

+0

Devo trasmettere il primo argomento a 'int'. Inoltre, quando lo faccio, il risultato viene passato al gestore 'ajax'' success', e non al gestore 'error'. È questo il comportamento previsto? –

4

In accordo con la risposta di aleho, ecco un esempio completo. Funziona come un fascino ed è molto semplice.

Controller cod

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

codice Javascript nella vista

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

Spero che questo aiuti qualcun altro!