Я посмотрел, как HttpContext создается в .NET Core. Затем я обнаружил, что существует класс с именем HttpContextFactory
, который создает и присваивает объект HttpContext
в свойство HttpContext
класса HttpContextAccessor
. И чтобы использовать объект HttpContext в нашем коде, мы вводим IHttpContextAccessor в конструктор класса, которому нужен объект.
Когда я смотрел на реализацию HttpContextAccessor, очевидно, что его свойство HttpContext получает значение объекта HttpContext из закрытой переменной AsyncLocal
, а позже 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 при создании библиотеки для моего проекта.