我一直在使用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());