首页 > 解决方案 > 对于 AddScoped(),“在同一个 HTTP 请求中”是什么意思

问题描述

我试图理解 和 之间的AddSingleton区别。有很多解释,但我无法理解,因为我不明白 HTTP 请求何时在同一范围内AddScopedAddTransient

标签: c#

解决方案


因此,AppDomain 或运行进程中的所有消费者都共享一个“根容器”。然后为每个 HTTP 请求创建子容器(在 ASP.NET Core 中,每个HttpContext包含HttpRequestHttpResponse)。(请注意,也可以出于其他原因创建子容器,但这不在此答案的关注范围内)。

  • Singleton服务只构建一次,通常只由根容器构建。它们就像 OOP 中的单例模式(一个类只能被实例化一次),除了在这种情况下您仍然可以手动创建多个实例,但 DI 容器本身只会创建 1 个实例。

    • 您可以通过从服务工厂方法返回 OOP 单例实例来将 OOP 单例与 DI 容器一起使用。
  • Transient服务总是在被请求时创建——它们是短暂的服务。一些容器会调用IDisposable.Dispose它创建的所有临时服务,而另一些则不会(因为他们希望消费者处理它们,请检查容器的策略)。

  • 请求范围的服务可以由不同的容器系统以不同的方式实现 - 但我看到的一种常见方法是在每个 HTTP 请求的开始(当创建一个新请求时HttpContext)创建一个子容器(一个子容器继承它的父对象),然后它创建的所有对象(通常作为单例,但仅在该子容器中)然后在 HTTP 请求结束时(如果HttpContext被销毁,在 HTTP 响应发送到客户端和响应结束)。

完全不考虑 ASP.NET - 假设我们有自己的 HTTP 服务器程序和自己的 DI 容器:

public class HttpServer
{
    private readonly IContainer rootContainer;

    public HttpServer()
    {
        this.rootContainer = RegisterServices( new ContainerBuilder() ).Build();

    }

    private static IContainerBuilder RegisterServices( IContainerBuilder services )
    {
        return services
            .RegisterSingleton<ISystemClock,BiosClock>()
            .RegisterSingleton<MySingleton>( factory: () => MySingleton.Instance )
            .RegisterTransient<IDbConnection>( factory: () => new SqlConnection() )
            .RegisterRequest<RequestTracingService>();
    }

    public void OnHttpRequest( Socket socket )
    {
        HttpContext context = new HttpContext();
        context.RequestContainer = this.rootContainer.CreateChildContainer();

        try
        {
            // hand-off the `context` object to code that reads the request, does processing, and then writes the response
        }
        finally
        {
            context.RequestContainer.Dispose(); // <-- this disposes of any objects created by RequestContainer during the processing of the request, without touching any objects created by `rootContainer`.
        }
    }
}

推荐阅读