是否对在整个 ASP.NET Core 3 应用程序中使用完全相同的 HTTPContextAccessor 实例感到困惑?

g.p*_*dou 2 dependency-injection httpcontext asp.net-core

我已经阅读了有关配置IHttpContextAccessorservices.AddSingleton范围的内容,但我也阅读了它正在“本地异步”工作,并且我也知道 ASP.Net 中异步的复杂工作,我的意思是例如,如果控制器操作方法是async,并且它await用于async调用,然后它可能会继续另一个线程,但神奇的是一些线程绑定的东西与维护(如HttpContext

我的具体用例:我必须MyConverter向我的 EF Core注入一个类,该类DbContextOnModelCreating. 然而,这个模型由 缓存DbContext,所以任何后续请求,即使它会有一个全新的实例,DbContext也会使用这个非常相同的模型,所以非常相同的MyConverter实例。(即使它已经配置services.AddTransient)。它MyConverter有一个构造函数和一个注入IHttpContextAccessor,因此基于非常相似的原因,它实际上也是所有DbContext/MyConverter用法的单例。

HttpContextAccessor在第一个请求中创建的这个特定实例将为 Web 应用程序生命周期中的所有后续请求提供服务。它会正常工作吗?这里有任何(并发)陷阱吗?

(我是否正确地认为我们使用单个或多个实例并不重要HttpContextAccessor,因为它的获取实现HttpContext将使用正确的方式,包括异步本地线程切换陷阱等以正确的方式返回HttpContext?)

gld*_*ael 8

简短回答:注册为services.AddHttpContextAccessor()然后你可以IHttpContextAccessor在任何你想要的地方注入,只要你在请求的执行上下文中使用它,它就会工作。例如,您无法读取不是由 HTTP 请求发起的代码的 HTTP 请求标头。


您是对的,IHttpContextAccessor应该将其注册为单身人士。建议不要自己做,而是使用AddHttpContextAccessor()扩展方法。请参阅此处的源代码。它在内部将 an 注册HttpContextAccessor为单例。

的代码HttpContextAccessor 可以在这里找到,我也在下面粘贴:

public class HttpContextAccessor : IHttpContextAccessor
{
    private static AsyncLocal<HttpContextHolder> _httpContextCurrent = new AsyncLocal<HttpContextHolder>();

    public HttpContext HttpContext
    {
        get
        {
            return  _httpContextCurrent.Value?.Context;
        }
        set
        {
            var holder = _httpContextCurrent.Value;
            if (holder != null)
            {
                // Clear current HttpContext trapped in the AsyncLocals, as its done.
                holder.Context = null;
            }

            if (value != null)
            {
                // Use an object indirection to hold the HttpContext in the AsyncLocal,
                // so it can be cleared in all ExecutionContexts when its cleared.
                _httpContextCurrent.Value = new HttpContextHolder { Context = value };
            }
        }
    }

    private class HttpContextHolder
    {
        public HttpContext Context;
    }
}
Run Code Online (Sandbox Code Playgroud)

由于HttpContextgetter 属性从异步本地字段返回,因此您始终获取HttpContext执行上下文的本地。

仅当已向 DI 注册时才HttpContext设置该字段。来源HttpContextFactory.Create()IHttpContextAccessor

并且HttpContextFactory.Create()[HostingApplication](https://github.com/aspnet/AspNetCore/blob/v2.2.5/src/Hosting/Hosting/src/Internal/HostingApplication.cs)设置上下文的位置调用。