2013-04-11 59 views
8

我一直在使用MVC4和EF5.x编写应用程序,并使用ELMAH记录异常以供审查。我们最近发布了这个应用程序,并且正如所期望的那样,ELMAH日志填满了几十个例外。伟大(而不是)!问题是,这些例外之一是如何使用ELMAH MVC记录EntityValidation错误?

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

当然,有没有办法看到的更多细节和堆栈跟踪包到我的SubmitChanges()

的EntityValidationErrors属性我知道ELMAH有允许我们提升自己的例外的能力,并以某种方式定制所记录的内容和方式。不幸的是,我对ELMAH和MVC仍然很陌生,Google搜索没有涉及任何相关内容。我确实发现a blog article关于登录EntityValidationErrors,作者特别提到他会在ELMAH中发布如何实现,但发布于2012年9月,之后我没有看到任何内容。

任何帮助将不胜感激!

回答

9

在这种情况下可能最好的做法是将context.SaveChanges();调用包装在try...catch块中,然后记录ValidationExceptions中的各个项目。像下面的东西应该让你开始:

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

为什么不仅赶上DbEntityValidationException而不是铸造? – 2013-12-23 16:46:19

+0

另外,您可以使用LINQ将所有错误选为字符串列表并加入,而不是选择第一个。 – 2014-02-08 07:28:17

+0

更为中心的解决方案将是首选。比如覆盖Elmah捕获错误的函数,并检查它是否为'DbValidationError',然后进一步研究它, – Zapnologica 2015-09-02 13:39:40

5

如何基于上述这种扩展方法..

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将有一个更好的异常,在它的日志

2

我将以下内容添加到我的Global.asax.cs以便跨我的MVC应用程序将所有DbEntityValidationException例外转发给Elmah:

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

部分代码从@Paige Cook's和@One10的帖子中重复使用。

+0

One can not add this in the filter section under app_start? – Zapnologica 2016-03-14 19:22:28

0

这里是我的执行工作ELMAH和EF验证错误全球的Web API的解决方案:

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

,然后我注册在WebApiConfig.cs文件下App_Start

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

重新投掷的属性下面的代码并不完美(虽然我不介意在这里重新设置调用堆栈,因为Elmah记录的地址的详细信息会显示导致该异常的原因),您将必须制定自己的安全隐含NS,但这是相当简洁&符合我的需要:

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