19

I want to create scoped container in asp.net core and use it in 2 methods of my singleton method.

I've tried create this in each method of sigleton. it works, but i think it is overhead.

var scopeFactory = _serviceProvider.GetService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var scopedContainer = scope.ServiceProvider;

I write it in each method when i need it. I think it is logic mistake. Please, explain me how to do it correct? thank you

Rey
  • 3,663
  • 3
  • 32
  • 55
Giacomo
  • 229
  • 1
  • 3
  • 11
  • 1
    Technically speaking. The mistake is likely that your service is a singleton in the first place. If it needs to use scoped services, there's a strong argument that it should be scoped as well. – Chris Pratt Mar 27 '19 at 18:21
  • The mistake is likely that you have many methods that require this logic. Only infrastructural components, part of your [Composition Root](https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/) should require this, which would lead to a handful (at most) of places where you would need to create a new scope. – Steven Mar 27 '19 at 19:37

1 Answers1

62

It is technically not incorrect the way you do it. If you are within a singleton service and you need to access scoped services, then you should create a new service scope and retrieve the services from that scope’s service provider. And when you are done, you should also dispose the scope.

In practice, you can simplify this a bit. You should avoid having to inject IServiceProvider directly into a service. Instead, you can just inject the IServiceScopeFactory directly. And then you should also create the scope with a using statement to make sure that it is disposed properly after use.

So an example singleton service could look like this:

public class ExampleSingletonService
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public ExampleSingletonService(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }

    public async Task DoSomethingAsync()
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var db = scope.ServiceProvider.GetService<MyDbContext>();

            db.Add(new Foo());
            await db.SaveChangesAsync();
        }
    }
}

As you can see, there isn’t really that much overhead for this. But of course this makes you think twice about whether you want to use a scoped service within a singleton or not.

poke
  • 369,085
  • 72
  • 557
  • 602