【问题标题】:How do I log EntityValidation errors using ELMAH MVC?如何使用 ELMAH MVC 记录 EntityValidation 错误?
【发布时间】:2013-04-03 04:08:25
【问题描述】:

我一直在使用 MVC4 和 EF5.x 编写应用程序,并使用 ELMAH 记录异常以供审查。我们最近发布了该应用程序,正如预期的那样,ELMAH 日志中充满了几十个异常。很棒(但不是)!问题是这些例外之一是

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

当然,无法查看 EntityValidationErrors 属性以获取更多详细信息,并且堆栈跟踪包含到我的 SubmitChanges()

我知道 ELMAH 能够让我们提出自己的异常,并以某种方式自定义记录的内容和方式。不幸的是,我对 ELMAH 和 MVC 还是很陌生,谷歌搜索并没有找到任何相关的东西。我确实在记录 EntityValidationErrors 时找到了a blog article,作者特别提到他会在 ELMAH 中发布如何做到这一点,但那是在 2012 年 9 月发布的,从那时起我什么也没看到。

任何帮助将不胜感激!

【问题讨论】:

    标签: asp.net-mvc-4 entity-framework-5 elmah elmah.mvc


    【解决方案1】:

    在这种情况下,最好的办法可能是将您的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);
    }
    

    【讨论】:

    • 为什么不只捕获 DbEntityValidationException 而不是强制转换?
    • 另外,您可以使用 LINQ 将所有错误选择为字符串列表并将它们连接起来,而不是选择第一个。
    • 首选更集中的解决方案。比如覆盖Elmah捕获错误的函数并检查它是否是DbValidationError然后进一步查看它,
    • 我这样做了,但是在我的较低级别,我捕获了验证异常并将它们包装在一个新的异常中并重新抛出。这样我就不需要在每个控制器或服务级别都需要这个,任何带有验证错误的异常现在都应该有信息。
    【解决方案2】:

    根据上面的这个扩展方法怎么样..

    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 的日志中会出现更好的异常

    【讨论】:

      【解决方案3】:

      我在 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 和@Original10 的帖子中重复使用。

      【讨论】:

      • 不能在 app_start 下的过滤器部分添加这个?
      【解决方案4】:

      这是我针对 Elmah 和 EF 验证错误的 Global 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());
      

      【讨论】:

        【解决方案5】:

        按照下面的代码重新抛出并不完美(尽管我不介意在此处重置调用堆栈,因为 Elmah 记录的发布地址的详细信息将向我显示导致异常的原因),您将不得不解决您自己的安全隐患,但这相当简洁并满足我的需求:

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

        【讨论】:

          猜你喜欢
          • 2016-10-12
          • 2011-11-18
          • 1970-01-01
          • 2018-03-20
          • 1970-01-01
          • 2010-10-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多