10

我一直在使用 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 的博客文章,作者特别提到他会在 ELMAH 中发布如何做到这一点,但那是在 2012 年 9 月发布的,从那时起我什么也没看到。

任何帮助将不胜感激!

4

5 回答 5

10

在这种情况下,最好的办法可能是将您的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);
}
于 2013-04-17T12:22:43.273 回答
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 在它的日志中会有一个更好的异常

于 2015-06-24T10:25:36.767 回答
3

Global.asax.cs为了将所有DbEntityValidationException异常转发到我的 MVC 应用程序中的 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 的帖子中重复使用的。

于 2015-06-29T07:57:12.817 回答
1

根据下面的代码重新抛出并不完美(尽管我不介意在此处重置调用堆栈,因为 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-09-13T01:45:36.230 回答
0

这是我针对 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());
于 2016-03-14T19:34:01.233 回答