Question

I have a application that uses IOC and DI to create and inject services.

I have a service layer that handles some business logic, in the service layer I have a repository that communicates with the database. That repository is using a DataContext which is not thread safe.

I want to run some functions on the service asynchronously using background tasks but know that this will cause issues with the repository. Thus I want the repository to be created for every background thread created. How is this achieved? I'm using StructureMap as the IoC.

public class Service : IService
{
    IRepository _repository;

    public Service(IRepository repository)
    {
        this._repository = repository;
    }

    public void DoSomething()
    {
        // Do Work
        _repository.Save();
    }
}


public class Controller
{
    IService _service;

    public Controller(IService service)
    {
        this._service = service;
    }

    public Action DoSomethingManyTimes()
    {
       for(int i =0; i < numberOfTimes; i++)
       {
           Task.Factory.StartNew(() =>
           {  
               _service.DoSomething();
           });
       }
    }
}
Was it helpful?

Solution

Some DI Containers (e.g. (IIIRC) StructureMap) actually support Per Thread lifetime styles, but that's probably not going to help you, because it would inject IService into Controller on one thread, and then use it on a number of other threads.

What I would suggest is to leave the Controller implementations as is, because the fact that a particular implementation of IService isn't thread-safe, is an implementation detail.

Instead, create a thread-safe Adapter/Decorator of IService and inject that into Controller. Something like this:

public ThreadSafeService : IService
{
    private readonly IServiceFactory factory;

    public ThreadSafeService(IServiceFactory factory)
    {
        this.factory = factory;
    }

    public void DoSomething()
    {
        this.factory.Create().DoSomething();
    }
}

IServiceFactory could be declared like this:

public interface IServiceFactory
{
    IService Create();
}

If you implement IServiceFactory so that it creates a new instance of IService for every call to Create, you have a thread-safe implementation on hand, because there's no shared state.

This approach is container-agnostic and prevents Leaky Abstractions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top