2013-04-11 15 views
8

Piszę aplikację przy użyciu MVC4 i EF5.x, i za pomocą ELMAH do rejestrowania wyjątków do przeglądu. Niedawno udostępniliśmy aplikację i zgodnie z oczekiwaniami dziennik ELMAH wypełnił kilkadziesiąt wyjątków. Świetne (i nie)! Problem polega na tym, że jeden z tych wyjątków jestJak rejestrować błędy EntityValidation za pomocą ELMAH MVC?

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

Oczywiście, nie ma sposobu, aby zobaczyć właściwości EntityValidationErrors więcej szczegółów i ślad stosu owija się do moich SubmitChanges()

wiem ELMAH ma Możliwość umożliwienia nam podniesienia własnych wyjątków oraz w jakiś sposób dostosowania tego, co jest rejestrowane i jak. Niestety, wciąż jestem nowy w ELMAH i MVC, a wyszukiwarka Google nie znalazła nic istotnego. Znalazłem a blog article podczas logowania EntityValidationErrors, a autor wyraźnie wspomniał, że zamieści to w ELMAH, ale zostało to opublikowane we wrześniu 2012 r. I od tamtej pory nic nie widziałem.

Każda pomoc będzie bardzo ceniona!

Odpowiedz

9

Prawdopodobnie najlepszą rzeczą do zrobienia w tym przypadku byłoby opakowywanie połączenia context.SaveChanges(); w bloku try...catch, a następnie rejestrowanie poszczególnych elementów z ValidationExceptions. Coś jak następujące powinny Ci zacząć:

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

Dlaczego nie tylko złapać DbEntityValidationException zamiast odlewania? –

+0

Możesz również użyć LINQ, aby wybrać wszystkie błędy jako listę ciągów i połączyć je zamiast wybierać pierwszy. –

+0

Bardziej centralne rozwiązanie byłoby preferowane. Takich jak nadpisanie funkcji, w której Elmah łapie błędy i sprawdzanie, czy jest to "DbValidationError", a następnie przyjrzymy się temu, – Zapnologica

5

Jak o tej metodzie wydłużania w oparciu o wyżej ..

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 będzie wtedy znacznie lepsze wyjątek to log

2

I dodałem do mojego Global.asax.cs, aby przekazać wszystkie wyjątki od DbEntityValidationException do Elmah w mojej aplikacji 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(); 
} 

Niektóre z tych kodów zostały ponownie użyte ze stanowisk @Paige Cook's i @ Original10.

+0

Nie można dodać tego w sekcji filtrów w obszarze app_start? – Zapnologica

0

Oto moja realizacja dla globalnego rozwiązania Web API dla ELMAH i EF walidacji błędów:

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

a następnie zarejestrować atrybut w pliku WebApiConfig.cs pod App_Start

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

Re rzucanie jako zgodnie z poniższym kodem nie jest doskonały (chociaż nie mam nic przeciwko resetowaniu stosu wywołań tutaj, ponieważ logowane przez Elmah szczegóły adresu, na który adres został wysłany, pokażą mi, co doprowadziło do wyjątku), a będziesz musiał opracować własne zabezpieczenie implicatio ns, ale to jest dość zwięzły & spełnia moje potrzeby:

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))))) 
    {} 
} 
Powiązane problemy