PostSharp OnExceptionAspect + EF 6 DbUpdateException

时间:2013-10-14 02:27:41

标签: entity-framework postsharp aop entity-framework-6

我正在使用PostSharp来处理Entity Framework 6异常。正如您在下面的代码中看到的,我正在处理两种不同的异常:

  • DbEntityValidationException
  • DbUpdateException

现在,我的HandleExceptionAttribute能够捕获所有DbEntityValidationException 但由于某些原因,只要EF抛出HandleExceptionAttribute

,就永远不会执行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});
}

1 个答案:

答案 0 :(得分:3)

PostSharp目前不支持async方法。他们宣布他们将从PostSharp 3.1开始支持async