New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessing scoped service in ConfigureServices in ASP.NET Core fails on IServiceScopeFactory #641

Open
andrebugs2 opened this Issue Dec 7, 2018 · 2 comments

Comments

2 participants
@andrebugs2
Copy link

andrebugs2 commented Dec 7, 2018

Hi,

I'm using Simple Injector with ASP.NET Core 2.2 with great success. I'm especially impressed with it's verification feature that prevents me from making mistakes. So first, thanks for the great software!

Now to my problem. I'm trying to access a scoped service (a regular service class that I have created) in ConfigureServices inside Startup.cs. The reason I need to do this is that is because I'm trying to register this service as a subscriber for messages coming from an EasyNetQ bus (RabbitMQ message bus). The service should take the message and save it to the database. My service (called AuditLogsService) therefore needs access to my DbContext, which is also scoped. Both my service and my DbContext are registered with Simple Injector (only). I cannot make my service singleton, since it needs to access the scoped DbContext.

Basically what I want to achive is this:

using (IServiceScope serviceScope = container.CreateScope())
{
    IServiceProvider serviceProvider = serviceScope.ServiceProvider;
    IAuditLogsService auditLogsService = serviceProvider.GetRequiredService<IAuditLogsService>();
    IBus messageBus = serviceProvider.GetRequiredService<IBus>();

    messageBus.SubscribeAsync<AuditLog>("Auditing", async message =>
                    await auditLogsService.SaveAsync(message));
}

container is the SimpleInjector container.

The call to container.CreateScope() gives me the following error:

System.InvalidOperationException: 'No service for type 'Microsoft.Extensions.DependencyInjection.IServiceScopeFactory' has been registered.'

If I instead use the built-in container in .NET Core the same thing works correctly, but I don't want to register all my own services there as well as in Simple Injector (although I guess I could use cross-wiring and only register them in the built-in one).

@dotnetjunkie

This comment has been minimized.

Copy link
Collaborator

dotnetjunkie commented Dec 7, 2018

The speudo code you presented above will not work, because it creates a scope once, while disposing it directly after you subscribed to the bus. This means that either all resolved services will be disposed once the lambda, registered using SubscribeAsync, gets executed, or at least, you will have one single object graph that will be reused for all messages that are sent to that lambda, making the used services singletons. In other words, the services will become Captive Dependencies. This can especially cause trouble when the lambda is executed in parallel.

The problem described above is independent of the used container; i.e. you will witness the same problems when using the MS.DI container.

Instead, each invocation of the registered lambda should create and manage a new scope. The required service should be resolved either from that scope (when using MS.DI) or within that scope (when using Simple Injector) as shown here:

IBus messageBus = ...

messageBus.SubscribeAsync<AuditLog>("Auditing", async message =>
{
    using (AsyncScopedLifestyle.BeginScope(this.container))
    {
        var auditLogsService = this.container.GetInstance<IAuditLogsService>();
        await auditLogsService.SaveAsync(message);
    }
}
@andrebugs2

This comment has been minimized.

Copy link

andrebugs2 commented Dec 7, 2018

Thank you so much for the explanation and fix Steven, it works perfectly. I had a feeling I was doing something fundamentally wrong, but couldn't figure out how to fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment