LogicalCallContext 在控制台应用中流过 await,但不是 VS UnitTest



我正在使用逻辑调用上下文将信息传回一系列等待。有趣的是,在我的测试控制台应用程序中,一切正常。但是,在 VS UnitTest 的上下文中运行我的单元测试时,调用上下文似乎不会流过等待。

在方法内部:正在设置调用上下文的 SendRequestAsyncImpl,当我在方法返回的那一刻从断点查询逻辑调用上下文时,调用上下文设置得很好。

但是,在等待之后返回以下行:

Message response = await SendRequestAsyncImpl(m, true).ConfigureAwait(false);

逻辑调用上下文为空。我想也许可以通过设置配置等待(真(而不是假来解决问题。但这并不能解决问题。

我尝试流动什么并不重要,甚至在 SendRequestAsyncImpl 中设置一个简单的值类型,例如:

System.Runtime.Remoting.Messaging.CallContext.LogicalSetData("flag", true);

在等待后无法检索。

为什么这在我的控制台应用中工作?但不是来自我的单元测试?有什么不同?(我见过其他一些涉及AppDomain问题的堆栈溢出问题。但我什至无法在等待中编组一个布尔。封送数据的能力似乎不是这里的问题。

因此,在阅读了Stephen Clear的评论之后,无论是在这个问题还是在文章中: http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html 答案已经很清楚了。

而在同步代码中,逻辑调用上下文确实从方法中流出。在异步方法中,CallContext 不会流出。这是有道理的,因为.NET怎么知道我希望在Task.WhenAll(...(之后如何合并CallContext。执行以下代码说明:

static void Main(string[] args)
{
    SynchronousCall();
    Task.WaitAll(Test(), Test2());
    var s = CallContext.LogicalGetData("SynchronousCall");
    var test = CallContext.LogicalGetData("Test");
    var test2 = CallContext.LogicalGetData("Test2");
    Console.WriteLine("s val: {0}", (s == null) ? "{null}" : s);
    Console.WriteLine("test val: {0}", (test == null) ? "{null}" : test);
    Console.WriteLine("test2 val: {0}", (test2 == null) ? "{null}" : test2);
}
private static void SynchronousCall()
{
    CallContext.LogicalSetData("SynchronousCall", true);
}
private static async Task<bool> Test()
{
    CallContext.LogicalSetData("Test", true);
    var b = await Task.Run<bool>(() => 
    {
        return true; 
    });
    return b;
}
private static async Task<bool> Test2()
{
    CallContext.LogicalSetData("Test2", true);
    var b = await Task.Run<bool>(() =>
    {
        return true;
    });
    return b;
}

打印以下内容:

s val: True
test val: {null}
test2 val: {null}

因此,如您所见,同步方法允许 CallContext 流出,但异步方法不允许。

修改了我的方法,以便在可等待方法之前将线程安全集合注入到 CallContext 中。我将信息注入该集合,而不是直接注入 CallContext。由于上游和下游都获取对同一集合的引用,因此这允许我在等待的方法返回后从集合中检索上下文,从而将上下文从等待的方法中向上流动

希望这对将来的其他人有所帮助。

最新更新