patterncsharpMinor
UnitOfWork for sending mail
Viewed 0 times
unitofworksendingmailfor
Problem
Topic is about a LoB web application written in C# for ASP.Net Core. We're following the blue book DDD architecture. We're using SimpleInjector as dependency injection container. Every request opens a new injection scope and implicitly a UnitOfWork and a database transaction which is committed/completed when the response leaves the business logic layer. Fine.
Now there is an application service, that requires control over the transaction and unit of work. The service is in charge of sending queued messages via SMTP, and since the SMTP communication takes some seconds for each mail, it should follow the pattern
I am now trying to show the most important parts how I managed this to happen, but I still have a bad feeling about this. Inside my
```
public class ExplicitScope : IDisposable
{
private readonly Container container;
private readonly Scope scope;
private readonly IUnitOfWork unitOfWork;
public ExplicitScope(Container container, bool withReadonlyUnitOfWork)
{
this.container = container;
scope = container.BeginExecutionContextScope();
unitOfWork = withReadonlyUnitOfWork
? container.GetInstance()
: container.GetInstance();
}
public T GetInstance() where T : class
{
return container.GetInstance();
}
public IEnumerable GetAllInst
Now there is an application service, that requires control over the transaction and unit of work. The service is in charge of sending queued messages via SMTP, and since the SMTP communication takes some seconds for each mail, it should follow the pattern
- Dequeue message
- Mark as "InProgress"
- Complete UnitOfWork
- Do the SMTP stuff
- Open new UnitOfWork
- Get the message, mark it as "Succeeded"
- Complete UnitOfWork
I am now trying to show the most important parts how I managed this to happen, but I still have a bad feeling about this. Inside my
SmtpSendingService the Scope is being used to get services from the injection container. The service is obviously lying about its dependencies, but the domain service instances that could have been injected via constructor would be stale after Completing and Reopening the scope.ExplicitScope: the instance that holds the current SimpleInjector Scope and the current IUnitOfWork instance```
public class ExplicitScope : IDisposable
{
private readonly Container container;
private readonly Scope scope;
private readonly IUnitOfWork unitOfWork;
public ExplicitScope(Container container, bool withReadonlyUnitOfWork)
{
this.container = container;
scope = container.BeginExecutionContextScope();
unitOfWork = withReadonlyUnitOfWork
? container.GetInstance()
: container.GetInstance();
}
public T GetInstance() where T : class
{
return container.GetInstance();
}
public IEnumerable GetAllInst
Solution
I don't know if this falls under "don't do it", but you shouldn't be passing your "container" around. That should be used to wire things up on startup. The rest of your classes should know nothing about it. That includes stuff like your "scope" class which calls
If the class needs to be able to get new instances, inject a factory. If the class needs an instance, inject an instance. Then you can easily test each class because you just insert a mock factory or mock instance etc.
GetInstance on the fly. They should take what they actually need (ideally through the constructor), not an IoC container which they use to resolve what they need. That's the Service Locator anti-pattern. If the class needs to be able to get new instances, inject a factory. If the class needs an instance, inject an instance. Then you can easily test each class because you just insert a mock factory or mock instance etc.
Context
StackExchange Code Review Q#158534, answer score: 5
Revisions (0)
No revisions yet.