2013-04-11 22 views
8

Ho scritto un'applicazione utilizzando MVC4 ed EF5.x e utilizzando ELMAH per la registrazione delle eccezioni per la revisione. Recentemente abbiamo rilasciato l'applicazione e, come previsto, il registro ELMAH si è riempito di diverse dozzine di eccezioni. Grande (e non)! Il problema è che una di queste due eccezioni èCome posso registrare gli errori EntityValidation usando ELMAH MVC?

System.Data.Entity.Validation.DbEntityValidationException 
Validation failed for one or more entities. 
See 'EntityValidationErrors' property for more details. 

Naturalmente, non c'è modo di vedere la proprietà EntityValidationErrors per maggiori dettagli e l'analisi dello stack avvolge ai miei SubmitChanges()

So ELMAH ha la capacità di permetterci di aumentare le nostre eccezioni e in qualche modo personalizzare ciò che viene registrato e come. Sfortunatamente, sono ancora molto nuovo per ELMAH e MVC e una ricerca su Google non ha rivelato nulla di rilevante. Ho trovato a blog article sulla registrazione di EntityValidationErrors, e l'autore ha specificamente menzionato che avrebbe pubblicato come farlo in ELMAH ma che è stato pubblicato nel settembre del 2012 e da allora non ho visto nulla.

Qualsiasi aiuto sarebbe molto apprezzato!

risposta

9

Probabilmente la cosa migliore da fare in questo caso sarebbe quella di avvolgere la tua chiamata context.SaveChanges(); in un blocco try...catch e quindi registrare i singoli elementi da ValidationExceptions. Qualcosa come il seguente dovrebbe iniziare:

try 
{ 
    context.SaveChanges(); 
} 
catch (DbEntityValidationException ve) 
{ 
    var error = ve.EntityValidationErrors.First().ValidationErrors.First(); 
    var msg = String.Format("Validation Error :: {0} - {1}", 
       error.PropertyName, error.ErrorMessage); 
    var elmahException = new Exception(msg); 

    Elmah.ErrorSignal.FromCurrentContext().Raise(elmahException); 
} 
+3

Perché non solo cattura DbEntityValidationException invece di casting? –

+0

Inoltre, è possibile utilizzare LINQ per selezionare tutti gli errori come un elenco di stringhe e unirle anziché selezionare il primo. –

+0

Si preferirebbe una soluzione più centrale. Ad esempio, ignorando la funzione in cui Elmah rileva gli errori e verifica se si tratta di un 'DbValidationError', quindi guarda oltre, – Zapnologica

5

ne dite di questo metodo di estensione in base a quanto sopra ..

public static void SaveChangesWithBetterValidityException(this DbContext context) 
    { 
     try 
     { 
      context.SaveChanges(); 
     } 
     catch (DbEntityValidationException ve) 
     { 
      var errors = new List<string>(); 
      foreach (var e in ve.EntityValidationErrors) 
      { 
       errors.AddRange(e.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage))); 
      } 
      var error = string.Join("\r\n", errors); 
      var betterException = new Exception(error, ve); 

      throw betterException; 
     } 
    } 

Elmah avrà quindi un'eccezione molto meglio nel suo log

2

I aggiunto il seguente al mio Global.asax.cs per inoltrare tutte le eccezioni DbEntityValidationException a Elmah attraverso la mia applicazione MVC:

private void ElmahEntityValidationException() 
{ 
    var dbEntityValidationException = Server.GetLastError() as DbEntityValidationException; 

    if (dbEntityValidationException != null) 
    { 
     var errors = new List<string>(); 
     foreach (var entityError in dbEntityValidationException.EntityValidationErrors) 
     { 
      errors.AddRange(entityError.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage))); 
     } 
     var error = string.Join("\r\n", errors); 
     var betterException = new Exception(error, dbEntityValidationException); 

     Elmah.ErrorSignal.FromCurrentContext().Raise(betterException); 
    } 
} 

protected void Application_Error(object sender, EventArgs e) 
{ 
    ElmahEntityValidationException(); 
} 

Alcuni di questo codice sono stati riutilizzati dai post di @Paige Cook e @ Original10.

+0

Non è possibile aggiungere questo nella sezione dei filtri in app_start? – Zapnologica

0

Qui è la mia applicazione per soluzione Web API globale per ELMAH e EF convalida errori:

public class ElmahHandleWebApiErrorAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    { 
     var e = context.Exception; 
     // Try parse as entity error (i'm not sure of performance implications here) 
     var efValidationError = e as DbEntityValidationException; 
     if (efValidationError == null) 
     { 
      RaiseErrorSignal(e); 
     } 
     else 
     { 
      RaiseEntityFrameWorkValidationErrorSignal(efValidationError); 
     } 
    } 

    private static bool RaiseErrorSignal(Exception e) 
    { 
     var context = HttpContext.Current; 
     if (context == null) 
      return false; 
     var signal = ErrorSignal.FromContext(context); 
     if (signal == null) 
      return false; 
     signal.Raise(e, context); 
     return true; 
    } 

    private static bool RaiseEntityFrameWorkValidationErrorSignal(DbEntityValidationException e) 
    { 
     var context = HttpContext.Current; 
     if (context == null) 
      return false; 
     var signal = ErrorSignal.FromContext(context); 
     if (signal == null) 
      return false; 

     //Taken from post above 
     var errors = new List<string>(); 
     foreach (var entityError in e.EntityValidationErrors) 
     { 
      errors.AddRange(entityError.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage))); 
     } 
     var error = string.Join("\r\n", errors); 
     var betterException = new Exception(error, e); 

     signal.Raise(betterException, context);   
     return true; 
    } 
} 

e poi mi registro l'attributo nel file WebApiConfig.cs sotto App_Start

config.Filters.Add(new ElmahHandleWebApiErrorAttribute()); 
1

Re-lancio come per il codice qui sotto non è perfetto (anche se non mi dispiace reimpostare lo stack delle chiamate qui, come i dettagli registrati di Elmah sull'indirizzo postato mi mostreranno cosa ha portato all'eccezione) e dovrai risolvere la tua implicazione di sicurezza ns, ma questo è abbastanza conciso & soddisfa le mie esigenze:

try 
{ 
    return base.SaveChanges(); 
} 
catch (DbEntityValidationException e) 
{ 
    var de = new DetailedEntityValidationException(e); 
    throw de; 
} 

public class DetailedEntityValidationException : Exception 
{ 
    public DetailedEntityValidationException(DbEntityValidationException ve) 
     : base(ve.Message + ":\r\n\t-" + string.Join(new string('-',20) + "\r\n\t-", ve.EntityValidationErrors.Select(ev=>string.Join("\r\n\t-",ev.ValidationErrors.Select(e=>e.ErrorMessage))))) 
    {} 
} 
Problemi correlati