通过静态 class 访问 HttpContext 适用于 "correctly" 不同的请求

Access to HttpContext via static class works "correctly" with different requests

我在尝试解决 non-controllers 中需要一些 headers 的问题时发现 this article
我对这种方法持怀疑态度,作者没有回应。我主要关心的是全局静态 HttpContext 的方法。我在想 不应该 处理两个请求。这种情况的一个例子如下(连同我提到的文章中介绍的方法):

public static class AppContext
{
    public static IHttpContextAccessor HttpContextAccessor { get; set; }
    public static void Configure(IHttpContextAccessor accessor)
    {
        HttpContextAccessor = accessor;
    }
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    IHttpContextAccessor contextAccessor)
{
    AppContext.Configure(contextAccessor);
    ...
}

[Route("api/[controller]")]
[ApiController]
public class ExampleController : ControllerBase
{
    [HttpGet("{number}")]
    public IActionResult Example(int number)
    {
        if (number == 1)
        {
            Thread.Sleep(10000);
        }

        var result = AppContext.HttpContextAccessor.HttpContext.Request.GetDisplayUrl();

        return Ok(result + " " + number);
    }
}

想提一下,作者使用名称 AppContext 作为这个静态 class,这正是我所期望的(那时它确实没用)。
然而,让我感到困惑的是实际的行为。我正在调试在 var result = ... 行放置断点的片段。我首先发送一个 number = 1 的请求,它会休眠一会儿,然后我发送第二个请求 number 的不同值。我跳过为第一个请求设置的断点并等待第一个请求(number = 1)停在那里。然后我检查 GetDisplayUrl() returns - 它 returns 一条带有 /1 的路径(这确实是这个已经睡了 10 秒的请求的路径)。我希望它以 /2 结尾,因为静态 class AppContextIHttpContextAccessor 的静态字段已被 ConfigureServices() 方法中的第二个请求重写。
我相信我遗漏了一些重要的东西,如果你也提供了一些我(和其他困惑的人)可以用来填补空白的资源,我会很高兴。
您能否再给我一些关于使用该方法的见解?可测试性是否受到影响(因为我在应用程序中到处使用静态 class)以及以何种方式?

这里发生了一些事情。从技术上讲,这会起作用,只是因为 IHttpContextAccessor 是一个单例。因此,将其保存在静态 ivar 上在技术上没有任何问题。无论哪种方式,它都会持续应用程序的生命周期。

HttpContext 本身是有范围的,但这不是此处设置的内容。因此,只要您有权访问 IHttpContextAccessor,从技术上讲,您就可以访问 HttpContext,尽管它可能为空,具体取决于您尝试访问的位置(即在请求管道之外)。

但是,这是一种糟糕的做法,甚至都不好笑。对于好的代码,应该在很大程度上避免静态。它们不可测试,它们用于隐藏依赖关系,使您的代码更难理解且更脆弱。

我看到有些人做了类似的事情,但那是为了让 HttpContext 本身看起来好像是静态的,目的只是支持假定静态 [=11] 的遗留代码=].该解决方案在那里无济于事,因为您必须以任何一种方式更改遗留代码。因此,它完全没有用。

如果您需要访问 HttpContext 本身存在的地方(例如控制器、页面和视图)之外的地方,那么只需在那里注入 IHttpContextAccessor,然后直接使用它。整件事 AppContext 就是个笑话,应该死在火里。