【问题标题】:ConfigureAwait(false) not making HttpContext NULL as expectedConfigureAwait(false) 未按预期使 HttpContext NULL
【发布时间】:2018-09-21 16:21:00
【问题描述】:

在使用async/await时,为了避免死锁,建议一直使用ConfigureAwait(false)直到最后一层。我知道使用 ConfigureAwait(false) 也会使当前的 HttpContext 为空。 Article

下面是示例代码,只是为了了解为什么ConfigureAwait(false) 没有在预期时将 HttpContext 设为 NULL,而在未预期时将其设为 NULL。

控制器

public class MyController : Controller
{
    private readonly MyService _service = new MyService();
    private readonly MyMapper _mapper = new MyMapper();        


    public async Task<ActionResult> DoSomething()
    {
        var data = await _service.GetData().ConfigureAwait(false);

        // EXPECTED: Below, HttpContext should NOT NULL
        // ACTUAL: HttpContext is NOT NULL as expected
        if (HttpContext == null)
        {
            throw new ArgumentNullException("context");
        }

        var model = _mapper.Map(data);

        return View(model);
    }
}

将数据源异步调用到 GetData 的服务

public class MyService
{
    public async Task<string> GetData()
    {
        // EXPECTED: HttpContext should be NULL here since we are calling 
        //this method from the Controller with ConfigureAwait(false)     

        // ACTUAL: HttpContext is NOT NULL, WHY?
        if(HttpContext.Current == null)
        {
            throw new ArgumentNullException("context");
        }

        using (var client = new HttpClient())
        {
            var response = await client.GetAsync("http://url").ConfigureAwait(false);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
        }
    }
}

映射器类将数据映射到模型

public class MyMapper
{
    public MyModel Map(string data)
    {
        // EXPECTED:  HttpContext should NOT NULL here since async call is already done.
        // ACTUAL: HttpContext is NULL here. WHY?
        if (HttpContext.Current == null)
        {
            throw new ArgumentNullException("context");
        };

        return new MyModel()
        {
            Message = data
        };
    }
}

HttpContext 在MyService 中应为NULL,在MyMapper 中应为NOT NULL,但事实并非如此。请在 MyServiceMyMapper 中查看我的内联 cmets

【问题讨论】:

    标签: c# .net asp.net-mvc async-await


    【解决方案1】:

    你有它倒退。 HttpContext.Current 将在上下文切换之后为空,而不是之前。

    所以:

    // ACTUAL: HttpContext is NOT NULL, WHY?
    if(HttpContext.Current == null)
    {
        throw new ArgumentNullException("context");
    }
    

    不,预计不是null,因为到目前为止还没有任何await(父await 不适用)。

    // EXPECTED:  HttpContext should NOT NULL here since async call is already done.
    // ACTUAL: HttpContext is NULL here. WHY?
    if (HttpContext.Current == null)
    

    切换发生在这一行之后

    var response = await client.GetAsync("http://url").ConfigureAwait(false);
    

    所以它应该是null

    【讨论】:

    • 在控制器操作方法中,AFTER 服务调用_service.GetData(...) 我正在检查 HttpContext 两次,1> 在操作方法中 2> 在映射器中。如果 HttpContext 在映射器中预计为空(如您所述),那么它在操作方法中也应该为空(但在操作方法中 HttpContext 不为空,然后它在映射器中变为 NULL。)。
    • @LP13 一件事是Controller.HttpContext 属性,它是在创建控制器时填充的。还有一点就是HttpContext.Current这个静态属性,和上下文切换前的Controller.HttpContext一样
    • 但不应该在异步调用完成后填充 HttpContext.Current 吗?
    • @LP13 不,因为它在另一个未填充的线程上运行。这就是为什么HttpContext.Current 是一个非常糟糕的主意并且在 ASP.NET Core 上不存在的原因
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 2017-06-06
    • 1970-01-01
    • 2013-09-11
    • 2018-02-08
    相关资源
    最近更新 更多