2013-04-11 10 views
8

Ich habe eine Anwendung mit MVC4 und EF5.x geschrieben und ELMAH zum Protokollieren von Ausnahmen zur Überprüfung verwendet. Wir haben die Anwendung vor kurzem freigegeben, und wie erwartet, füllte sich das ELMAH-Protokoll mit mehreren Dutzend Ausnahmen. Großartig (und nicht)! Das Problem ist, dass eine dieser Ausnahme istWie melde ich EntityValidation Fehler mit ELMAH MVC?

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

Natürlich gibt es keine Möglichkeit, die EntityValidationErrors Eigenschaft für weitere Details und der Stack-Trace wickelt bis zu meinem SubmitChanges()

Ich weiß ELMAH hat das zu sehen Fähigkeit, uns zu erlauben, unsere eigenen Ausnahmen zu erheben, und in irgendeiner Weise anzupassen, was eingeloggt wird und wie. Leider bin ich immer noch sehr neu bei ELMAH und MVC und eine Google-Suche ergab nichts Relevantes. Ich fand a blog article auf Logging EntityValidationErrors, und der Autor erwähnt ausdrücklich, dass er wie in ELMAH, aber das wurde im September 2012 veröffentlicht wurde, und ich habe nichts seitdem gesehen.

Jede Hilfe würde sehr geschätzt werden!

Antwort

9

Wahrscheinlich die beste Sache in diesem Fall zu tun wäre, Ihren context.SaveChanges(); Anruf in einen try...catch Block zu wickeln und dann die einzelnen Elemente von den ValidationExceptions zu protokollieren. So etwas wie die folgenden sollten Sie beginnen:

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

Warum nur nicht fangen DbEntityValidationException statt Gießen? –

+0

Sie können auch LINQ verwenden, um alle Fehler als eine Liste von Zeichenfolgen auszuwählen und ihnen beizutreten, anstatt die erste Zeichenfolge auszuwählen. –

+0

Eine zentralere Lösung wäre bevorzugt. Wie zum Beispiel das Überschreiben der Funktion, wo Elmah die Fehler abfängt und prüft, ob es ein 'DbValidationError' ist, dann schaue es weiter an, – Zapnologica

5

Wie über diese Erweiterungsmethode basiert auf dem oben ..

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 dann haben eine viel bessere Ausnahme in sie log ist

2

I zu meiner Global.asax.cs hinzugefügt, um alle DbEntityValidationException Ausnahmen zu Elmah über meine MVC-Anwendung:

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

Ein Teil dieses Codes wurde in @ Paige Cooks und @ Original10s Posts wiederverwendet.

+0

Kann man das nicht im Filterbereich unter app_start hinzufügen? – Zapnologica

0

Hier ist meine Implementierung für Lösung Global Web-API für Elmah und EF Validierungsfehler:

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

und dann melde ich das Attribut in der WebApiConfig.cs Datei unter App_Start

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

Re Werfen als Der unten stehende Code ist nicht perfekt (obwohl es mir nichts ausmacht, den Call-Stack hier zurückzusetzen, da Elmahs geloggte Details der Adresse, die ich gepostet habe, mir zeigen würde, was zu der Exception führte), und Sie müssen Ihre eigenen Sicherheitsaspekte ausarbeiten ns, aber das ist ziemlich prägnante & meine Bedürfnisse erfüllt:

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