具有AsyncLocal与范围服务的Singleton [英] Singleton with AsyncLocal vs Scope Service

查看:62
本文介绍了具有AsyncLocal与范围服务的Singleton的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

https://github.com/aspnet/AspNetCore/blob/master/src/Http/Http/src/HttpContextAccessor.cs

 //版权所有(c).NET Foundation.版权所有.//根据Apache许可2.0版获得许可.有关许可证信息,请参阅项目根目录中的License.txt.使用System.Threading;命名空间Microsoft.AspNetCore.Http{公共类HttpContextAccessor:IHttpContextAccessor{私有静态AsyncLocal< HttpContextHolder>_httpContextCurrent =新的AsyncLocal< HttpContextHolder>();公共HttpContext HttpContext{得到{返回_httpContextCurrent.Value?.Context;}放{varholder = _httpContextCurrent.Value;如果(持有人!= null){//清除困在AsyncLocals中的当前HttpContext,以完成此操作.owner.Context = null;}如果(值!=空){//使用对象间接方式将HttpContext保留在AsyncLocal中,//,以便在清除后可以在所有ExecutionContexts中清除它._httpContextCurrent.Value =新的HttpContextHolder {上下文=值};}}}私有类HttpContextHolder{公共HttpContext上下文;}}} 

我很好奇,以这种方式代替使用 Scope 服务有什么好处?在我看来,两者都将使对象在请求范围内可用.

如果它是一个范围服务,我认为HttpContextAccessor会看起来像这样

 使用System.Threading;命名空间Microsoft.AspNetCore.Http{公共类HttpContextAccessor:IHttpContextAccessor{私有HttpContextHolder _httpContextCurrent;公共HttpContext HttpContext{得到{返回_httpContextCurrent?.Context;}放{如果(值!=空){_httpContextCurrent =新的HttpContextHolder {上下文=值};}}}私有类HttpContextHolder{公共HttpContext上下文;}}} 

然后将其用作范围服务

  services.TryAddScope< IHttpContextAccessor,HttpContextAccessor>(); 

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

解决方案

只要是单例,则解析后的 IHttpContextAccessor 实例可以由单例服务永久保存并正常运行,同时它如果单例服务解析范围为 IHttpContextAccessor 的内容,可能会导致问题.

I looked at how HttpContext being created in .NET Core. Then I found that there is a class called HttpContextFactory which create and assign HttpContext object into a HttpContext property of HttpContextAccessor class. And to use HttpContext object in our code, we inject IHttpContextAccessor to the constructor of the class that needs the object.

When I looked at the implementation of HttpContextAccessor, apparently its HttpContext property gets the HttpContext object value from a private AsyncLocal variable and later on HttpContextAccessor is registered as Singleton.

https://github.com/aspnet/AspNetCore/blob/master/src/Http/Http/src/HttpContextAccessor.cs

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading;

namespace Microsoft.AspNetCore.Http
{
    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;
        }
    }
}

I'm curious, what is the benefit of doing it this way instead of using a Scope service? It seems to me both would make the object available within a request scope.

If it's a scope service, I reckon the HttpContextAccessor will look something like this

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;
        }
    }
}

Then use it as scope service

services.TryAddScope<IHttpContextAccessor, HttpContextAccessor>();

I would like to know what are the advantages and disadvantages for each approach, so that I'll understand when to use Singleton with AsyncLocal or Scope when creating a library for my project.

解决方案

As long as it is a singleton, the resolved IHttpContextAccessor instance could be holded permanently by a singleton service and work properly, while it could cause problems if a singleton service resolves a scoped IHttpContextAccessor.

这篇关于具有AsyncLocal与范围服务的Singleton的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆