Royi Namir
Royi Namir

Reputation: 148524

Scoped service DI & GC in .net CORE - Clarification?

My Startup.cs file is :

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddHttpContextAccessor();
            services.AddScoped<IFoo,Foo>();   // Notice Scoped service
        }

Please notice that IFoo is a scoped service.

IFoo is a simple service :

 public interface IFoo
    {
        public int Get(int id)
        {
            return id;
        }
    }

    public class Foo : IFoo
    {
    }

And here is the simple contoller :

public class WeatherForecastController : ControllerBase
{
    private readonly IHttpContextAccessor _accessor;


    private readonly IFoo _fooService;

    public WeatherForecastController(IFoo fooService, IHttpContextAccessor accessor)
    {
        _fooService = fooService;
        _accessor = accessor;
    }

    [HttpGet]
    public async Task<int[]> Get()
    {
        async Task Foo()
        {
            try
            {
                await Task.Delay(4000);
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                Console.WriteLine("***Service******" + _fooService.Get(4));
            }
            catch (Exception e)
            {
                Console.Write(e);
            }
        }

        Foo(); // non awaitable
        return new[] { 0 };
    }
}

Please notice that Foo() is without await.

Now, When I run the code , I DO see the result of the scoped service being accessed after the request has completed ( since Foo is not awaited) :

enter image description here

I was expecting to see Null reference exception since it's a scoped service that is executed a long time after the main request thread has executed.

MSDN :

enter image description here Question:

Why am I not getting a null reference exception?
Scoped service is only per request. and the request has finished long time before it was accessed by the task.

Upvotes: 2

Views: 437

Answers (1)

Jes&#250;s L&#243;pez
Jes&#250;s L&#243;pez

Reputation: 9221

Scoped services are disposed when the scope is disposed, that doesn't mean that all references to scoped services become null. That means that the scope calls Dispose() method on all disposable objects that are created inside the scope. When you call a method on an object that has been disposed the object should raise ObjectDisposedException, you should not get NullReferenceException.

Try with the following and you will see that ObjectDisposedException is thrown:

public interface IFoo
{
    public int Get(int id)
    {
        return id;
    }
}

public class Foo: IFoo, IDisposable
{

    public bool IsDisposed { get; private set; }
    public void Dispose()
    {
        if (!IsDisposed)
        {
            IsDisposed = true;
        }
    }

    private void CheckDisposed()
    {
        if (IsDisposed) throw new ObjectDisposedException(nameof(Foo));
    }

    public int Get(int id)
    {
        CheckDisposed();
        return id;
    }
    
}

Upvotes: 1

Related Questions