通过静态类访问HttpContext可以“正确”处理不同的请求

时间:2019-08-21 13:03:55

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

我在尝试解决非控制器中需要一些标头的问题时发现了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);
    }
}

想提到作者为此静态类使用名称 App 上下文,而这正是我所期望的(那时确实没用)。
但是,令我困惑的是实际行为。我正在调试将断点放在var result = ...行的那一部分。我首先发送一个number = 1的请求,该请求将休眠一会儿,然后我发送另一个具有number值的第二个请求。我跳过为第一个请求放置的断点,并等待第一个请求(number = 1)在那里停止。然后,我检查GetDisplayUrl()返回的内容-它返回一个带有/1的路径(这实际上是该请求已休眠10秒的路径)。我希望它以/2结尾,因为静态类IHttpContextAccessor的{​​{1}}的静态字段已被AppContext方法中的第二个请求重写。
我相信我错过了一些至关重要的事情,如果您还提供一些我(以及其他困惑的人)可以用来填补空白的资源,我将感到很高兴。
您能否再给我一些使用该方法的见解?可测试性会受到影响吗(因为我在应用程序中的任何地方都使用静态类)?

1 个答案:

答案 0 :(得分:4)

这里发生了一些事情。从技术上讲,这将起作用,仅因为IHttpContextAccessor是单例。因此,将其保留在静态ivar上在技术上没有任何错误。无论哪种方式,它都可以延长应用程序的寿命。

HttpContext本身是有作用域的,但这不是此处设置的。因此,只要您有权访问IHttpContextAccessor,就可以从技术上获得对HttpContext的访问权限,尽管它可能为null,具体取决于您尝试执行的操作(即在请求管道之外)。 / p>

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

我已经看到有些人做了类似的事情,但这是为了使HttpContext本身看起来像是静态的,其目的仅是支持假定静态HttpContext的旧代码。 。此解决方案对此无济于事,因为您必须以任何一种方式更改旧代码。因此,这完全没有用。

如果您需要访问HttpContext的内在位置,例如控制器,页面和视图,则只需在其中插入IHttpContextAccessor,然后直接使用即可。 AppContext这件事全是个玩笑,应该在火中死掉。