2013-10-14 86 views
1

我正在使用PostSharp處理實體框架6異常。正如你可以在代碼中看到下面我處理兩種不同類型的異常:PostSharp OnExceptionAspect + EF 6 DbUpdateException

  • DbEntityValidationException
  • DbUpdateException

現在,我HandleExceptionAttribute能夠捕獲所有DbEntityValidationException
但由於某些原因,HandleExceptionAttribute永遠不會執行,每當EF投擲一個DbUpdateException

這是我的代碼,讓你有tter理解:

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}); 
} 

回答

2

PostSharp目前不支持async方法。他們宣佈他們將支持從PostSharp 3.1開始的async

+0

所以我猜數據驗證不是異步執行的。任何(乾淨)我可以在這期間做什麼? – Moon

+0

有一個解決方法:您可以使用方法攔截屬性來應用您的異常處理邏輯,但這需要您深入研究'async'方法的編譯器生成類型的細節。這非常麻煩,需要PostSharp的付費版本,並且確實限制瞭如何組播這些屬性。 –