.net CORE 中的范围服务 DI 和 GC - 澄清?
Scoped service DI & GC in .net CORE - Clarification?
我的 Startup.cs
文件是:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHttpContextAccessor();
services.AddScoped<IFoo,Foo>(); // Notice Scoped service
}
请注意 IFoo
是一个范围内的服务。
IFoo
是一项简单的服务:
public interface IFoo
{
public int Get(int id)
{
return id;
}
}
public class Foo : IFoo
{
}
这是简单的控制器:
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 };
}
}
请注意 Foo()
没有 await
。
现在,当我 运行 代码时,我确实看到了在请求完成后访问范围服务的结果(因为没有等待 Foo
):
我期待看到 Null 引用异常,因为它是一个作用域服务,在主请求线程执行后很长时间才执行。
MSDN:
问题:
为什么我没有收到空引用异常?
范围服务仅按请求提供。并且请求在被任务访问之前已经完成了很长时间。
作用域服务在释放范围时也被释放,这并不意味着对作用域服务的所有引用都变为空。这意味着作用域对在作用域内创建的所有一次性对象调用 Dispose() 方法。当您在已处置的对象上调用方法时,该对象应该引发 ObjectDisposedException
,您不应该得到 NullReferenceException
.
尝试以下操作,您会看到 ObjectDisposedException
被抛出:
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;
}
}
我的 Startup.cs
文件是:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddHttpContextAccessor();
services.AddScoped<IFoo,Foo>(); // Notice Scoped service
}
请注意 IFoo
是一个范围内的服务。
IFoo
是一项简单的服务:
public interface IFoo
{
public int Get(int id)
{
return id;
}
}
public class Foo : IFoo
{
}
这是简单的控制器:
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 };
}
}
请注意 Foo()
没有 await
。
现在,当我 运行 代码时,我确实看到了在请求完成后访问范围服务的结果(因为没有等待 Foo
):
我期待看到 Null 引用异常,因为它是一个作用域服务,在主请求线程执行后很长时间才执行。
MSDN:
为什么我没有收到空引用异常?
范围服务仅按请求提供。并且请求在被任务访问之前已经完成了很长时间。
作用域服务在释放范围时也被释放,这并不意味着对作用域服务的所有引用都变为空。这意味着作用域对在作用域内创建的所有一次性对象调用 Dispose() 方法。当您在已处置的对象上调用方法时,该对象应该引发 ObjectDisposedException
,您不应该得到 NullReferenceException
.
尝试以下操作,您会看到 ObjectDisposedException
被抛出:
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;
}
}