我如何使用ELMAH MVC记录EntityValidation错误



我一直在使用MVC4和EF5编写应用程序。并使用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月发布的,从那时起我就没有看到任何东西。

任何帮助都将非常感激!

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

基于上面的扩展方法如何…

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("rn", errors);
            var betterException = new Exception(error, ve);
            throw betterException;
        }
    }

Elmah在日志

中将有一个更好的异常

我在我的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("rn", errors);
        var betterException = new Exception(error, dbEntityValidationException);
        Elmah.ErrorSignal.FromCurrentContext().Raise(betterException);
    }
}
protected void Application_Error(object sender, EventArgs e)
{
    ElmahEntityValidationException();
}

其中一些代码是从@Paige Cook和@Original10的帖子中重用的。

按照下面的代码重新抛出是不完美的(尽管我不介意在这里重置调用堆栈,因为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 + ":rnt-" + string.Join(new string('-',20) + "rnt-", ve.EntityValidationErrors.Select(ev=>string.Join("rnt-",ev.ValidationErrors.Select(e=>e.ErrorMessage)))))
    {}
}

这是我对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("rn", errors);
       var betterException = new Exception(error, e);
       signal.Raise(betterException, context);        
       return true;
   }
}

然后在App_Start

下的WebApiConfig.cs文件中注册属性
config.Filters.Add(new ElmahHandleWebApiErrorAttribute());

最新更新