我正在使用 PostSharp 处理 Entity Framework 6 异常。正如您在下面的代码中看到的那样,我正在处理两种不同的异常:
- DbEntityValidationException
- 数据库更新异常
现在,我HandleExceptionAttribute
能够捕获所有DbEntityValidationException
但由于某种原因,HandleExceptionAttribute
每当 EF 抛出一个DbUpdateException
这是我的代码,以便您更好地理解:
HandleExceptionAttribute.cs
[Serializable]
public class HandleExceptionAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
Exception exception = args.Exception;
var validationException = exception as DbEntityValidationException;
if (validationException != null)
{
HandleDataValidationException(validationException);
}
var updateException = exception as DbUpdateException;
if (updateException != null)
{
HandleDataUpdateException(updateException);
}
throw exception;
}
private void HandleDataUpdateException(DbUpdateException exception)
{
Exception innerException = exception.InnerException;
while (innerException.InnerException != null)
{
innerException = innerException.InnerException;
}
throw new Exception(innerException.Message);
}
private void HandleDataValidationException(DbEntityValidationException exception)
{
var stringBuilder = new StringBuilder();
foreach (DbEntityValidationResult result in exception.EntityValidationErrors)
{
foreach (DbValidationError error in result.ValidationErrors)
{
stringBuilder.AppendFormat("{0} [{1}]: {2}",
result.Entry.Entity.ToString().Split('.').Last(), error.PropertyName, error.ErrorMessage);
stringBuilder.AppendLine();
}
}
throw new Exception(stringBuilder.ToString().Trim());
}
}
MyContext.cs
public class MyContext : DbContext
{
public MyContext () : base(Settings.Get(Settings.DB_CONNECTION_STRING)) { }
public DbSet<Subscriber> Subscribers { get; set; }
private void SetCreatedAtUpdatedAt()
{
foreach (DbEntityEntry entityEntry in ChangeTracker.Entries())
{
switch (entityEntry.State)
{
case EntityState.Added:
((IEntity) entityEntry.Entity).CreatedAt = DateTime.Now;
break;
case EntityState.Modified:
((IEntity) entityEntry.Entity).UpdatedAt = DateTime.Now;
break;
}
}
}
[HandleException]
public override int SaveChanges()
{
SetCreatedAtUpdatedAt();
return base.SaveChanges();
}
[HandleException]
public override Task<int> SaveChangesAsync()
{
SetCreatedAtUpdatedAt();
return base.SaveChangesAsync();
}
}
行动
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Subscribe(string email)
{
string message = null;
bool success = false;
try
{
using (var context = new MyContext())
{
context.Subscribers.Add(
new Subscriber
{
Email = email
});
await context.SaveChangesAsync();
}
await _queueManager.Enque(
QueueNames.TASK_SEND_EMAIL,
new BrokeredMessage(email),
Settings.Get(Settings.SB_CN_TASKS_SEND));
success = true;
}
catch (Exception exception)
{
// Whenever there is a DbUpdateException, it does not get
// filtered and processed by PostSharp Exception Handler
// I have a unique index constraint on the "Email" field of the Subscriber.
// So when I try to add a duplicate subscriber, EF raises DbUpdateException
// This exception should have been filtered by PostSharp since I have
// overridden and decorated "SaveChangesAsync()" method in my DbContext
// with [HandleException]
// On the other hand, I also have [Required] for "Email" in my POCO.
// So, when I don't pass in any email address for the subscriber,
// EF raises DbEntityValidationException -- this does get processed
// by the PostSharp Exception Handler
message = exception.Message;
}
return Json(new {message, success});
}