HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

UnitOfWork for sending mail

Submitted by: @import:stackexchange-codereview··
0
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

  • 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 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.