【问题标题】:Access to HttpContext via static class works "correctly" with different requests通过静态类访问 HttpContext 可以“正确”处理不同的请求
【发布时间】:2019-12-26 18:34:30
【问题描述】:

我在尝试解决需要非控制器中的某些标头的问题时找到了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,这正是我所期望的(那时确实没用)。
但是,让我感到困惑的是实际行为。我正在调试在var result = ... 行放置断点的部分。我首先发送一个带有number = 1 的请求,该请求将休眠一段时间,然后我发送另一个带有number 值的请求。我跳过为第一个请求放置的断点并等待第一个请求(number = 1)停在那里。然后我检查 GetDisplayUrl() 返回的内容 - 它返回一个带有 /1 的路径(这确实是这个请求的路径,已经休眠了 10 秒)。我希望它以/2 结尾,因为静态类AppContextIHttpContextAccessor 的静态字段已被ConfigureServices() 方法中的第二个请求重写。
我相信我遗漏了一些重要的东西,如果您还提供一些我(和其他人困惑的)可以用来填补空白的资源,我会很高兴。
您能否也给我一些有关使用该方法的更多见解?可测试性是否会受到影响(因为我在应用程序中的任何地方都使用静态类)以及以何种方式受到影响?

【问题讨论】:

  • 具体的上下文访问器可以从代码运行的线程中确定正确的上下文。尝试在完全不同的线程中使用它时,您将无法获得正确的上下文。
  • 但是,出现了问题。对于我们需要访问会话的每个组件,我们必须注入IHttpContextAccessor 的依赖项。虽然对于一两个组件来说这不是问题,但如果我们必须一遍又一遍地做同样的事情,那可能会非常令人生畏。在本文中,我们将使用不同的方法来实现相同的目的。在这种方法中,我们将创建一个静态 AppContext 类。 这本身就是一个警告信号。通过另一个类抽象IHttpContextAccessor#HttpContext 有什么意义,你要公开相同的HttpContext...

标签: c# asp.net-core httpcontext static-classes


【解决方案1】:

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

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

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

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

如果您需要在控制器、页面和视图等其固有存在的地方之外访问HttpContext,则只需在其中注入IHttpContextAccessor,并直接使用它。这整个AppContext 是个笑话,应该死在火里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-05
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2016-01-11
    相关资源
    最近更新 更多