2017-08-20 11 views
0

私はSendAsyncメソッドを使用して電子メールを送信するWindowsサービスを実装しています。30秒ごとに20のバッチでメールを送信します。ここではEF6とSQL Server 2016を使用していますイベントでUoWとDbContextが失敗する

EmailRepository.cs

public class EmailRepository : IEmailRepository 
{ 
    private BBEntities db = null; 


    public EmailRepository(BBEntities db) 
    { 
     this.db = db; 
    } 

    public IEnumerable<tb_Email> SelectAll(int batchAge, int batchSize) 
    { 
     DateTime tDate = DateTime.Now.AddMinutes(batchAge); 
     return db.tb_Email.Where(x => x.ReadyToSend.Equals(true) & x.DateSent.Equals(null) & x.DateCreated >= tDate).OrderBy(x => x.DateCreated).Take(batchSize); 
    } 

    public tb_Email SelectByID(Guid id) 
    { 
     return db.tb_Email.Find(id); 
    } 

    public void Update(tb_Email obj) 
    { 
     db.Entry(obj).State = EntityState.Modified; 
    } 

    #region IDisposable Support 
    private bool disposedValue = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposedValue) 
     { 
      if (disposing) 
      { 
       db.Dispose(); 
      } 
      disposedValue = true; 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    #endregion 
} 

UnitOfWork.cs

public class UnitOfWork : IUnitOfWork 
{ 

    private readonly BBEntities ctx = new BBEntities(); 
    private IEmailRepository emailRepository; 

    public IEmailRepository EmailRepository 
    { 
     get 
     { 

      if (this.emailRepository == null) 
      { 
       this.emailRepository = new EmailRepository(ctx); 
      } 
      return emailRepository; 
     } 
    } 

    public void Dispose() 
    { 
     this.ctx.Dispose(); 
    } 


    public void Commit() 
    { 
     this.ctx.SaveChanges(); 
    } 

} 

EmailService.cs

public class EmailService : IEmailService 
{ 

    private IUnitOfWork unitOfWork; 

    public EmailService() 
    { 
     unitOfWork = new UnitOfWork(); 
    } 

    public List<tb_Email> SelectAll(int batchAge, int batchSize) 
    { 
     return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList(); 
    } 

    public tb_Email SelectByID(Guid id) 
    { 
      return unitOfWork.EmailRepository.SelectByID(id); 
    } 

    public void Update(tb_Email obj) 
    { 
     using (unitOfWork = new UnitOfWork()) 
     { 
      unitOfWork.EmailRepository.Update(obj); 
      unitOfWork.Commit(); 
     } 
    } 

} 

SMTPService.cs

public class SMTPService : ISMTPService 
    { 

     SmtpClient client; 
     MailMessage newMessage; 
     EmailService emailService; 
     IEventLoggerService MailCheckerLog; 


     public SMTPService() 
     { 
      emailService = new EmailService(); 
      MailCheckerLog = new EventLoggerService(); 

     } 



     public void SendEmail(tb_Email email) 
     { 

      try 
      {// rest of the code ..... 

       newMessage = new MailMessage(); 

       newMessage.Headers.Add("X-Email_Id", email.Id.ToString()); 


       client.SendCompleted += (sender, e) => SendCompletedCallback(sender, e); 

       tb_Email userState = email; 


       // 
       // if I put the update database logic here, it works fine 
       // 


       client.SendAsync(newMessage, userState); 

      } 
      catch (Exception e) 
      { 
       MailCheckerLog.log("Error in SendComplete event handler - Exception: " + e.Message.ToString() + " -- InnerException: " + e.InnerException.Message, EventLogEntryType.Error); 
       client.Dispose(); 
       newMessage.Dispose(); 
       throw; 
      } 

     } 
     void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
     { 

      tb_Email email = (tb_Email)e.UserState; 
      Console.WriteLine("----------------------------------" + emailID.Id); 
      email.ReadyToSend = false; 
      emailService.Update(email); 

      client.Dispose(); 
      newMessage.Dispose(); 

     } 

    } 

問題:

だから私は実行する電子メールを送信して処理するためのsendEmailと単純なループ内のメソッドtb_Emailオブジェクトのリスト。各電子メールが送信されると、データベースを更新する必要があります。これを行うには SendCompletedイベントは各電子メールのために少し後解雇かもしれませんが、私は多くの電子メールを、システムが先に行くSendAsyncを使用して処理していて、私は、私のSendCompletedイベントに

 email.ReadyToSend = false; 
     emailService.Update(email); 

を使用しています。それは私が更新方法のための私のUOWインスタンスにusingステートメントを使用していますユニークな単一dbContextを使用していることを確認する 。これは、私はいくつかの成功のアップデート後にイベントに入れただし場合は、(私は電子メールが正常かどうかに送信されたかどうかを知る必要があるとして、任意の意味がありません)私は直接のsendEmail方法で私の更新ロジックを置く場合は正常に動作しますそれだけで

System.Data.Entity.Core.EntityExceptionを投げる:「基になるプロバイダーがOpenで失敗しました。」

私は実際には各操作のための新しいコンテキストを作成していたときにそれが可能であるかを理解していません。私はそれを自分自身に答えなければなら

+0

た文は、例外がスローされますか? – ashin

+0

これはthis.ctx.SaveChanges()です。 UoWクラスで – user65248

答えて

0

申し訳ありませんが、問題は、UOW変数は、まだ他のスレッドによって使用されていたということでしたので、解決策は

以下のように、更新メソッド内で使用して文のための新しい変数を宣言することです
public class EmailService : IEmailService 
{ 

    private IUnitOfWork unitOfWork; 

    public EmailService() 
    { 
     unitOfWork = new UnitOfWork(); 
    } 

    public List<tb_Email> SelectAll(int batchAge, int batchSize) 
    { 
     return unitOfWork.EmailRepository.SelectAll(batchAge, batchSize).ToList(); 
    } 

    public tb_Email SelectByID(Guid id) 
    { 
      return unitOfWork.EmailRepository.SelectByID(id); 
    } 

    public void Update(tb_Email obj) 
    { 
     IUnitOfWork unitOfWorkUpdate; 
     using (unitOfWorkUpdate = new UnitOfWork()) 
     { 
      unitOfWorkUpdate.EmailRepository.Update(obj); 
      unitOfWorkUpdate.Commit(); 
     } 
    } 

} 
関連する問題