ConfigureAwait(false)丢失对象的上下文

时间:2018-10-08 17:51:05

标签: c# http asynchronous async-await httphandler

在我的程序中,我正在发出请求,并记录了请求和响应。 但是使用ConfigureAwait(false)可能会丢失我的"logger"对象的上下文,该对象将请求记录在一个文件中,并将响应记录在另一个文件中。

try
{
    logger.VerboseRequest(tokenParameters.Endpoint, payloadJson, options);
    serializedResponse = await httpHandler.PostAsync<string>
                        (tokenParameters.Endpoint, payloadJson, options, cts.Token)
                        .ConfigureAwait(false);
}
catch (TaskCanceledException)
{
    throw new TokenTimeoutException();
}
catch (Exception ex)
{
    logger.Error(String.Format("Error when posting to Endpoint: {0}",ex.Message));
    throw;
}

知道为什么会这样吗?还是要避免这种情况?

通过删除ConfigureAwait(false),我可能会遇到超时问题,因此这不是一种选择。

1 个答案:

答案 0 :(得分:1)

这是设计使然,因此您必须问自己: “我这样做正确吗?”

有多种方法可以解决该问题。如果您想要可记录的即发即忘异步调用,可以将其包装在这样的调用中。但是请注意,任务可能在不同的上下文中运行,因此您可能无法访问典型的上下文绑定变量,例如当前的HttpContext(以及类似的东西)。

Task.Run(async () => 
{
    try
    {
        logger.VerboseRequest(tokenParameters.Endpoint, payloadJson, options);
        serializedResponse = await httpHandler.PostAsync<string>
                                 (tokenParameters.Endpoint, payloadJson, options, cts.Token);
    }
    catch (TaskCanceledException)
    {
        throw new TokenTimeoutException();
    }
    catch (Exception ex)
    {
        logger.Error(String.Format("Error when posting to Endpoint: {0}",ex.Message));
        throw;
    }
}).ConfigureAwait(false);


甚至更好:将其包装在函数中

async Task DoStuff()
{
    try
    {
        logger.VerboseRequest(tokenParameters.Endpoint, payloadJson, options);
        serializedResponse = await httpHandler.PostAsync<string>
                                 (tokenParameters.Endpoint, payloadJson, options, cts.Token);
    }
    catch (TaskCanceledException)
    {
        throw new TokenTimeoutException();
    }
    catch (Exception ex)
    {
        logger.Error(String.Format("Error when posting to Endpoint: {0}",ex.Message));
        throw;
    }
}

您当前的代码在哪里:

async Task WhereYouAreDoingStuff()
{
    DoStuff().ConfigureAwait(false);
}