c# - AsyncLocal 与 ASP.NET Core Controller /ServiceProviderScope

标签 c# .net asp.net-core dependency-injection .net-core

在 Controller 作用域中解析的元素上调用 Dispose 之前,执行上下文似乎不会保留。这可能是由于 asp.net core 必须在 native 代码和托管代码之间跳转,并在每次跳转时重置执行上下文。似乎在处理作用域之前,不再恢复正确的上下文。

以下内容演示了该问题 - 只需将其放入默认的 asp.net core 示例项目中并将 TestRepo 注册为 transient 依赖项即可。

当调用 GET api/values/ 时,我们在调用开始时在静态 AsyncLocal 中将当前任务的值设置为 5。该值按预期流经等待,没有任何问题。但是,当 Controller 及其依赖项在调用后被释放时,AsyncLocal 上下文已经重置。

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly TestRepo _testRepo;

    public ValuesController(TestRepo testRepo) => _testRepo = testRepo;

    [HttpGet()]
    public async Task<IActionResult> Get()
    {
        _testRepo.SetValue(5);
        await Task.Delay(100);
        var val = _testRepo.GetValue(); // val here has correctly 5.
        return Ok();
    }
}

public class TestRepo : IDisposable
{
    private static readonly AsyncLocal<int?> _asyncLocal = new AsyncLocal<int?>();

    public int? GetValue() => _asyncLocal.Value;

    public void SetValue(int x) => _asyncLocal.Value = x;

    public void Foo() => SetValue(5);

    public void Dispose()
    {
        if (GetValue() == null)
        {
            throw new InvalidOperationException(); //GetValue() should be 5 here :(
        }
    }
}

这是故意的吗?如果是的话,有什么解决方法可以解决这个问题吗?

最佳答案

您所看到的行为是 ASP.NET Core 工作方式中的一个不幸的怪癖。我不清楚 Microsoft 为什么选择这种行为,但它似乎是从 Web API 的工作方式复制的,它具有确切的行为。显然,处理是在请求结束时完成的,但由于某种原因,异步上下文在此之前已被清除,因此无法在单个异步上下文中运行完整的请求。

你基本上有两个选择:

  1. 不使用环境状态来共享状态,而是通过对象图流动状态而不是使用环境状态。换句话说,使 TestRepo确定范围并存储 value在私有(private)领域。
  2. 将使用该值的操作移至请求的早期阶段。例如,您可以定义一些包装请求并在最后调用该操作的中间件。在此阶段,异步上下文仍然存在。

一些 DI 容器实际上应用了第二种技术。例如,简单注入(inject)器使用基于环境状态的范围,使用 AsyncLocal<T>在幕后。当集成到 ASP.NET Core 中时,它将把请求包装在应用此范围的中间件中。这意味着从简单注入(inject)器解析的任何作用域组件都将在 ASP.NET Core 管道处置其服务之前被处置,并且这种情况会在异步上下文仍然可用时发生。

关于c# - AsyncLocal 与 ASP.NET Core Controller /ServiceProviderScope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50968004/

相关文章:

c# - 关系数据库的全文搜索?

c# - 如何分割一个字节[]

c# - 与桌面应用程序捆绑在一起的视频的 DRM?

c# - 如何升级 Entity Framework 5 Code First 的 DataAnnotations

c# - 配置 ASP.NET Core 应用程序的正确顺序是什么?

c# - 流畅的 nhibernate 复制一个完整的实体

c# - c#中特殊字符的正则表达式

.net - Authbot 登录服务返回链接,显示 "ClientID not supported for this API"

ubuntu - Visual Studio Code Ubuntu aspnet core 2 容器调试

c# - POST 请求响应 404,而 GET 请求工作正常 .NET Core、React