J'utilise NHibernate, DI/IoC et le modèle de l'unité de travail.
La plupart des exemples de travail non rémunéré que j'ai vus garantissent qu'il ne peut y avoir qu'un seul travail non rémunéré/session actif en même temps, par exemple celui-ci y celui-ci .
Malheureusement, je ne comprends pas encore très bien comment je dois gérer deux services qui utilisent tous deux l'UoW, mais dont l'un appelle l'autre.
Prenons l'exemple suivant :
Un logger qui utilise un UoW :
public class LoggerService : ILoggerService
{
private ILoggerRepository repo;
public LoggerService(ILoggerRepository Repo)
{
this.repo = Repo;
}
public void WriteLog(string message)
{
using (UnitOfWork.Start())
{
// write log
}
}
}
...et un autre service qui utilise également un UoW ET qui appelle l'enregistreur :
public class PlaceOrderService : IPlaceOrderService
{
private IOrderRepository repo;
private ILoggerService service;
public PlaceOrderService(IOrderRepository Repo, ILoggerService Service)
{
this.repo = Repo;
this.service = Service;
}
public int PlaceOrder(int orderNumber)
{
using (UnitOfWork.Start())
{
// do stuff
this.service.WriteLog("Order placed!"); // will throw exception!!
// do more stuff
}
}
}
Si mon implémentation de l'UoW s'assure qu'il n'y a qu'un seul UoW actif en même temps (et lève une exception si vous essayez d'en démarrer un autre, comme dans les deux exemples cités), mon code se plantera dans la section this.service.WriteLog
dans la méthode PlaceOrder :
La méthode PlaceOrder a déjà créé un deuxième objet utilitaire actif et la méthode WriteLog tente d'en ouvrir un second, de sorte que l'implémentation de l'objet utilitaire lève une exception à ce sujet.
Alors, que puis-je faire ?
J'ai trouvé deux idées, mais toutes deux me semblent quelque peu "bidon".
-
Ne pas démarrer un nouvel UoW dans le LoggerService, mais supposer qu'il y en a déjà un actif dans le code appelant.
C'est ce que je fais en ce moment. Je viens de supprimer leusing (UnitOfWork.Start())
à partir du LoggerService et s'assurer que l'on ne peut pas appeler directement le LoggerService, mais seulement à partir d'autres services.
Cela signifie que le code ci-dessus fonctionnera, mais que le LoggerService se plantera si le code appelant ne démarre pas un UoW, car le LoggerService suppose qu'il en existe déjà un. -
Laissez le code de l'exemple tel quel, mais modifiez l'implémentation de UoW.Start() comme suit :
a) s'il n'y a pas d'OMU actif, en créer un nouveau
b) s'il existe déjà est un CGU actif, renvoyer celui-ci
Cela me permettrait d'appeler le LoggerService directement ET à partir d'autres services, qu'il y ait déjà un UoW ou non.
Mais je n'ai jamais rien vu de tel dans aucun exemple sur le net.
(Et dans cet exemple, il n'y a que deux services. Cela pourrait être beaucoup plus compliqué, il suffit de penser à un PlaceSpecialOrderService
qui effectue quelques opérations spéciales et appelle ensuite PlaceOrderService.PlaceOrder()
...)
Des conseils ?
Merci d'avance !
EDIT :
Merci pour les réponses apportées jusqu'à présent.
D'accord, l'exploitation forestière n'était peut-être pas le meilleur exemple.
Je comprends votre point de vue concernant l'utilisation d'une session séparée pour la journalisation, et je vais y jeter un coup d'œil et l'essayer.
Quoi qu'il en soit, je dois encore trouver un moyen de faire fonctionner les appels de service imbriqués.
Imaginez un autre exemple au lieu de l'enregistrement, comme l'exemple PlaceSpecialOrderService que j'ai mentionné plus haut.
Aux personnes qui ont répondu à la question de savoir si je devais commencer mon travail non rémunéré quelque part dans l'infrastructure, et pas directement dans les services, j'ai répondu par l'affirmative :
D'un côté, c'est logique, mais d'un autre côté, cela signifierait évidemment que je ne peux pas effectuer deux transactions différentes en un seul appel de service.
Il faudra que j'y réfléchisse, car je suis certain que j'en aurai besoin quelque part (par exemple : enregistrer une commande dans une transaction, puis faire d'autres choses dans une seconde transaction, et même si cela échoue, la commande n'est pas annulée).
Avez-vous procédé de cette manière (un utilisateur par appel de service) dans vos applications ?
N'avez-vous jamais eu besoin de la possibilité de lancer un deuxième UoW dans le même appel de service ?