首页 > 解决方案 > 带有 AsyncLocal 与 Scope 服务的单例

问题描述

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

当我查看 HttpContextAccessor 的实现时,显然它的 HttpContext 属性从私有AsyncLocal变量中获取 HttpContext 对象值,后来 HttpContextAccessor 被注册为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;
        }
    }
}

我很好奇,这样做而不是使用Scope服务有什么好处?在我看来,两者都会使对象在请求范围内可用。

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

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>();

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

标签: c#asp.net-core.net-corehttpcontext

解决方案


只要它是单例,解析的IHttpContextAccessor实例就可以由单例服务永久持有并正常工作,而如果单例服务解析范围内的IHttpContextAccessor.


推荐阅读