Skip to content

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

@royvandertuuk

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");
}

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