Using IServiceScopeFactory without implementing the Service Locator Pattern
I'm of the opinion that this is awesome, and I have a couple of suggestions to add. It's not "Service Locator" because you're explicitly constraining to the exact type that can be resolved---the explicit dependency is right up there in the constructor.

(I wish they'd bake this into .Net Core.)


Don't store the service-object


I think it would be better to replace T Service with T GetRequiredService(). If you're resolving a Transient service, it would be useful. Additionally, it makes for fewer changes when someone switches away from the built-in IServiceScopeFactory.

Finish implementing IDispose


See this answer on StackOverflow

Go Singleton


I see no reason to register as Scoped, considering what this does. It's using a Singleton, so make it Singleton.



Here's my tweaked version

public interface IServiceScopeFactory&lt;T&gt; where T : class
{
    IServiceScope&lt;T&gt; CreateScope();
}

public interface IServiceScope&lt;T&gt; : IDisposable where T : class
{
    T GetRequiredService();
    T GetService();
    IEnumerable&lt;T&gt; GetServices();
}


public class ServiceScopeFactory&lt;T&gt; : IServiceScopeFactory&lt;T&gt; where T : class
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public ServiceScopeFactory(IServiceScopeFactory serviceScopeFactory) =&gt; _serviceScopeFactory = serviceScopeFactory;

    public IServiceScope&lt;T&gt; CreateScope() =&gt; new ServiceScope&lt;T&gt;(_serviceScopeFactory.CreateScope());
}

public class ServiceScope&lt;T&gt; : IServiceScope&lt;T&gt; where T : class
{
    readonly IServiceScope _scope;

    public ServiceScope(IServiceScope scope) =&gt; _scope = scope;

    public T GetRequiredService() =&gt; _scope.ServiceProvider.GetRequiredService&lt;T&gt;();

    public T GetService() =&gt; _scope.ServiceProvider.GetService&lt;T&gt;();

    public IEnumerable&lt;T&gt; GetServices() =&gt; _scope.ServiceProvider.GetServices&lt;T&gt;();


    #region IDisposable/Dispose methods ( https://stackoverflow.com/a/538238/530545 )
    bool _disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool calledFromCodeNotTheGarbageCollector)
    {
        if (_disposed)
            return;
        if (calledFromCodeNotTheGarbageCollector)
        {
            // dispose of manged resources in here
            _scope?.Dispose();
        }
        _disposed = true;
    }

    ~ServiceScope() { Dispose(false); }
    #endregion

}


You'd register this like so:

services.AddSingleton(typeof(IServiceScopeFactory&lt;&gt;), typeof(ServiceScopeFactory&lt;&gt;));


And to work with your example, you'd use it like so (assuming you registered your ConmaniaDbContext):

public class Foo
{
    readonly IServiceScopeFactory&lt;ConmaniaDbContext&gt; _dbCtxFactory;

    public Foo(IServiceScopeFactory&lt;ConmaniaDbContext&gt; dbCtxFactory) =&gt; _dbCtxFactory = dbCtxFactory;

    public void Bar()
    {
        using var scope = _dbCtxFactory.CreateScope();
        var db = scope.GetRequiredService();
        //use service
    }
}


FYI/Backstory

FYI, I'm using this in a .Net Core 3.x app that's leveraging Gql.Net. This pattern makes it so I can actually use EFC. Gql.Net's field resolvers run in parallel, so if you don't do something like this, you cannot use your constructor-injected DbContext in more than one field, or you wind up getting this EFC exception (which is not unique to Gql.Net): 


  [InvalidOperationException] A second operation started on this context
  before a previous operation completed. This is usually caused by
  different threads using the same instance of DbContext. For more
  information on how to avoid threading issues with DbContext, see
  https://go.microsoft.com/fwlink/?linkid=2097913.


I've confirmed this solves that "parallel execution in the same Http request" issue for me. I can now run multiple, concurrent tasks against the database from the same instance of a scoped service class. It's because with this solution, instead of all threads using the same DbContext that was injected into the constructor, they now each resolve their own, scoped DbContext instance when they need it.