Skip to content

Scoped lifetime is not working as expected when using Cross wiring with ASP.NET Core web applications #26

Description

@royvandertuuk

Creating a AsyncScopedLifestyle scope inside of a ASP.NET Core web request does not result in a new scoped service when this service is resolved via Simple Injector ASP.NET Core cross wiring. Instead, it is resolving the same instance as in the other scope.

I could only reproduce this issue in a ASP.NET Core app, I have attached a solution (Cross wiring issue.zip) that demonstrates the issue.

Below a snippet that produces the issue:

Resolve using cross wiring
The CoreScopedService is registered in the ServiceCollection and cross wired using Simple Injector.
Throws because scopedService1 and scopedService2 are the same instance.

CoreScopedService scopedService1;
CoreScopedService scopedService2;

using (var scope = AsyncScopedLifestyle.BeginScope(Startup.Container))
{
    scopedService1 = scope.Container.GetInstance<CoreScopedService>();
}

using (var scope = AsyncScopedLifestyle.BeginScope(Startup.Container))
{
    scopedService2 = scope.Container.GetInstance<CoreScopedService>();
}

if (object.ReferenceEquals(scopedService1, scopedService2))
{
    throw new InvalidOperationException("Same scoped service instance");
}

The same scenario is working in the following cases:

Defer resolving the instances until after the web request
Does not throw, scopedService1 and scopedService 2 are separate instances.

 Task.Run(() =>
{
    // Sleep so resolving is done after the request has been completed.
    Thread.Sleep(1000);

    CoreScopedService scopedService1;
    CoreScopedService scopedService2;

    using (var scope = AsyncScopedLifestyle.BeginScope(Startup.Container))
    {
        scopedService1 = scope.Container.GetInstance<CoreScopedService>();
    }

    using (var scope = AsyncScopedLifestyle.BeginScope(Startup.Container))
    {
        scopedService2 = scope.Container.GetInstance<CoreScopedService>();
    }

    if (object.ReferenceEquals(scopedService1, scopedService2))
    {
        throw new InvalidOperationException("Same scoped service instance");
    }
});

Using SimpleInjector only
Does not throw, scopedService1 and scopedService 2 are separate instances.

SimpleInjectorScopedService scopedService1;
SimpleInjectorScopedService scopedService2;

using (var scope = AsyncScopedLifestyle.BeginScope(Startup.Container))
{
    scopedService1 = scope.Container.GetInstance<SimpleInjectorScopedService>();
}

using (var scope = AsyncScopedLifestyle.BeginScope(Startup.Container))
{
    scopedService2 = scope.Container.GetInstance<SimpleInjectorScopedService>();
}

if (object.ReferenceEquals(scopedService1, scopedService2))
{
    throw new InvalidOperationException("Same scoped service instance");
}

Using only ASP.NET Core DI
Does not throw, scopedService1 and scopedService 2 are separate instances.

CoreScopedService scopedService1;
CoreScopedService scopedService2;

using (var scope = _serviceScopeFactory.CreateScope())
{
    scopedService1 = scope.ServiceProvider.GetRequiredService<CoreScopedService>();
}

using (var scope = _serviceScopeFactory.CreateScope())
{
    scopedService2 = scope.ServiceProvider.GetRequiredService<CoreScopedService>();
}

if (object.ReferenceEquals(scopedService1, scopedService2))
{
    throw new InvalidOperationException("Same scoped service instance");
}

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions