1

J'ai une méthode Update dans ma classe qui contient une instruction using pour créer une nouvelle instance de UnitOfWork, car j'envoie des emails de manière asynchrone et comme EF et DbContext ne sont pas thread safe doivent créer un nouveau dbContext pour chaque requête. J'ai utilisé Autofac pour DI dans mon UnitOfWork mais je ne sais pas comment utiliser mon nouveau constructeur UnitOfWork en utilisant statement pour m'assurer qu'il crée une nouvelle instance. Veuillez noter qu'il s'agit d'une application console. MerciAutofac DI dans Utilisation des instructions

UnitOfWork.cs

public class UnitOfWork : IUnitOfWork 
{ 

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

    public UnitOfWork(IEventLoggerService MaLog, IEmailRepository emailRepo) 
    { 
     emailRepository = emailRepo; 
     MailCheckerLog = MaLog; 
    } 

    public IEmailRepository EmailRepository 
    { 
     get 
     { 

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

    public void Commit() 
    { 
     try 
     { 
      this.ctx.SaveChanges(); 
     } 
     catch (Exception e) 
     { 
      MailCheckerLog.log("Unit Of Work Exception => Commit() => " + e.Message.ToString(), EventLogEntryType.Error); 
     } 
    } 

} 

EmailService.cs

public class EmailService : IEmailService 
    { 

     private IUnitOfWork unitOfWork; 
     private IEventLoggerService MailCheckerLog; 
     private ISMTPService SMTPService; 

     public EmailService(IEventLoggerService Log, IUnitOfWork uOfWork, ISMTPService SMTPS) 
     { 
      unitOfWork = uOfWork; 
      MailCheckerLog = Log; 
      SMTPService = SMTPS; 
      SMTPService.OnMailSendComplete += new EventHandler(SendCompletedC); 
     } 




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

Mise à jour:

Je l'ai travailler avec la solution suivante cependant pas sûr si c'est le meilleur chemin

UnitOfWorkFactory.cs

public class UnitOfWorkFacotry : IUnitOfWorkFactory 
{ 

    private IUnitOfWork uow; 
    private IEmailRepository emailrepo; 
    private IEventLoggerService eventlog; 

    public UnitOfWorkFacotry(IEventLoggerService MaLog, IEmailRepository emailRep) 
    { 

     emailrepo = emailRep; 
     eventlog = MaLog; 
    } 

    public IUnitOfWork GetCurrent() 
    { 
     return uow ?? create(); 
    } 

    public IUnitOfWork create() 
    { 
     return new UnitOfWork(eventlog, emailrepo); 
    } 

} 

EmailService.cs -> méthode de mise à jour

public void Update(tb_Email obj) 
    { 
     IUnitOfWork unitOfWork2; 
     using (unitOfWork2 = unitOfWorkFactory.create()) 
     { 
      unitOfWork2.EmailRepository.Update(obj); 
      unitOfWork2.Commit(); 
     } 
    } 
+0

Est-ce que 'ISMTPService' est juste un wrapper autour des frameworks' SmtpClient'? Si c'est le cas, sachez que vous ne pouvez pas envoyer plusieurs mails simultanément même avec les méthodes asynchrones, le code doit attendre que chaque appel/mail soit terminé avant d'en commencer un nouveau. En bref, si vous voulez utiliser cette librairie, il vaut mieux utiliser les méthodes synchrones. – Igor

+0

Oui, ainsi qu'une méthode pour envoyer l'email et un événement. – user65248

+0

Mais c'est exactement ce dont j'avais besoin et ça fonctionne bien. Le code envoie les e-mails au serveur et plus tard, il va augmenter et événement si l'envoi a été réussi ou non et sur la base de ce que j'utilise la méthode de mise à jour pour mettre à jour la base de données. – user65248

Répondre

0

Bien que je n'aime pas la mise en œuvre actuelle du modèle UOW et dépôt dans votre exemple, je pense que vous pouvez résoudre votre problème en ajoutant une méthode appelée BeginTransaction() ou quelque chose de similaire.

De cette façon, vous pouvez simplement injecter le UnitOfWork et commencer à l'utiliser. Cela vous donne également un peu plus de souplesse sur le moment de commencer une transaction et d'ajouter une certaine logique supplémentaire dans vos méthodes peut-être.

Dans votre cas, je pense que cela devrait ressembler au bloc de code suivant.

public interface IUnitOfWork : IDispose 
{ 
    void BeginTransaction(); 
    void Commit(); 
} 


public class EmailService : IEmailService 
{ 

    private IUnitOfWork unitOfWork; 
    private IEventLoggerService MailCheckerLog; 
    private ISMTPService SMTPService; 

    public EmailService(... IUnitOfWork unitOfWork ..) 
    { 
     this.unitOfWork = unitOfWork; 
     //Other stuff 
    } 

    public void Update(tb_Email obj) 
    { 
     IUnitOfWork unitOfWork2; 
     using (unitOfWork2.BeginTransaction()) 
     { 
      unitOfWork2.EmailRepository.Update(obj); 
      unitOfWork2.Commit(); 
     } 
    } 
} 

Personnellement, je suis plus fan de la suggestion de Derek Greer (le Unit of Work Decorator) qu'il explique très bien dans ce post: https://lostechies.com/derekgreer/2015/11/01/survey-of-entity-framework-unit-of-work-patterns/ C'est un peu plus complexe par rapport aux implémentations « réguliers », mais beaucoup plus propre À mon avis. Pas pour promouvoir mon propre blog, mais j'ai écrit un post à propos de cette façon de mettre en œuvre avec Autofac.

Le code le plus important de cet article est le suivant.

//Registration 
builder.RegisterGeneric(typeof(IncomingFileHandler<>)).Named("commandHandler", typeof(IIncomingFileHandler<>)); 
builder.RegisterGenericDecorator(typeof(IncomingFileHandlerTransactionDecorator<>), typeof(IIncomingFileHandler<>), fromKey: "commandHandler"); 

//The unit of work decorator 
public class IncomingFileHandlerTransactionDecorator<TCommand> : IIncomingFileHandler<TCommand> 
    where TCommand : IncomingFileCommand 
{ 
    private readonly IIncomingFileHandler<TCommand> decorated; 
    private readonly IDbContext context; 

    public IncomingFileHandlerTransactionDecorator(IIncomingFileHandler<TCommand> decorated, IDbContext context) 
    { 
     this.decorated = decorated; 
     this.context = context; 
    } 

    public void Handle(TCommand command) 
    { 
     using (var transaction = context.BeginTransaction()) 
     { 
      try 
      { 
       decorated.Handle(command) 

       context.SaveChanges(); 
       context.Commit(transaction); 
      } 
      catch (Exception ex) 
      { 
       context.Rollback(transaction); 
       throw; 
      } 
     } 
    } 
} 
+0

Pouvez-vous s'il vous plaît expliquer votre solution? Aussi quel est le problème avec le modèle UoW et repo? – user65248

+0

Merci, je suis encore confus à ce sujet, vu l'article et il mentionne aussi qu'une autre façon est de créer une Usine UoW, mes questions sont comment puis-je transmettre mes paramètres (en Autofac) au constructeur UoW ​​pendant que je suis créer une nouvelle instance UoWFactory. Mon UoW a besoin d'au moins un service injecté qui est le EventLoggerService. – user65248