C# 具有异步本地vs作用域服务的单例

C# 具有异步本地vs作用域服务的单例,c#,asp.net-core,.net-core,httpcontext,C#,Asp.net Core,.net Core,Httpcontext,我研究了如何在.NETCore中创建HttpContext。然后我发现有一个名为HttpContextFactory的类,它创建HttpContext对象并将其分配到HttpContext类的HttpContextAccessor属性中。为了在代码中使用HttpContext对象,我们将IHttpContextAccessor注入到需要该对象的类的构造函数中 当我查看HttpContextAccessor的实现时,显然它的HttpContext属性从私有的AsyncLocal变量获取HttpCo

我研究了如何在.NETCore中创建HttpContext。然后我发现有一个名为
HttpContextFactory
的类,它创建
HttpContext
对象并将其分配到
HttpContext
类的
HttpContextAccessor
属性中。为了在代码中使用HttpContext对象,我们将IHttpContextAccessor注入到需要该对象的类的构造函数中

当我查看HttpContextAccessor的实现时,显然它的HttpContext属性从私有的
AsyncLocal
变量获取HttpContext对象值,然后HttpContextAccessor注册为Singleton

然后将其用作范围服务

services.TryAddScope<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddScope();

我想知道每种方法的优缺点,以便在为我的项目创建库时了解何时将Singleton与AsyncLocal或Scope一起使用。

只要它是Singleton,已解析的
IHttpContextAccessor
实例可以由单例服务永久保留并正常工作,虽然如果单例服务解决作用域
IHttpContextAccessor

可能会导致问题,但我想其中一个原因可能是Asp.Net Core IServiceProvider不允许在单例类中注入作用域依赖项。这可能是背后的一个重大决定。如果事情应该按照您的建议确定范围,那么所有使用它的类可能都必须确定范围。但有趣的是,一旦请求被送达,HTTPContext将变为null。

如果您查看此文件,我想您误解了我的问题
IHttpContextAccessor
已注册为singleton。这是因为它们使用
AsyncLocal
将HttpContext对象存储在
HttpContextAccessor
类中。我想问的是,如果IHttpContextAccessor注册为作用域,而AsyncLocal不用于在HttpContextAccessor类中存储HttpContext,那么有什么区别呢。
DefaultHttpContextFactory
本身没有注册为
Singleton
,而是注册为
Transient
,正如您在这个文件中看到的那样。这个类负责设置HttpContext的值。如果你的意思是,这个类被设置为singleton,这样每当我们在项目中创建自己的singleton类时,我们都可以在那里插入
IHttpContextAccessor
。这有点道理:)但是我可以问一下我们什么时候需要从我们的web项目中的单例类访问
IHttpContextAccessor
?至于一些有状态的服务,它们可能有一些必须在请求中调用的方法(这意味着在方法调用的作用域中对象有单例生存期),根据singleton store服务,使其成为一个服务而不是作用域服务可能很有用。@Alsien可能是因为asp.net core中的IServiceProvider不允许在singleton中注入作用域服务,所以HttpContextAccessor被设置为具有asynclocal而不是建议的作用域的singleton。
using System.Threading;

namespace Microsoft.AspNetCore.Http
{
    public class HttpContextAccessor : IHttpContextAccessor
    {
        private HttpContextHolder _httpContextCurrent;

        public HttpContext HttpContext
        {
            get
            {
                return  _httpContextCurrent?.Context;
            }
            set
            {
                if (value != null)
                {
                    _httpContextCurrent = new HttpContextHolder { Context = value };
                }
            }
        }

        private class HttpContextHolder
        {
            public HttpContext Context;
        }
    }
}
services.TryAddScope<IHttpContextAccessor, HttpContextAccessor>();