LogicalCallContext 在 Console App 中流过 await 但不是 VS UnitTest
LogicalCallContext flows across await in Console App but not VS UnitTest
我正在使用 Logical CallContext 在一系列等待中回流信息。有趣的是,在我的测试控制台应用程序中,一切正常。但是,当 运行 我在 VS UnitTest 的上下文中进行单元测试时,调用上下文似乎没有流过等待。
方法内部:SendRequestAsyncImpl 正在设置调用上下文,当我在方法 returns 的那一刻从断点查询逻辑调用上下文时,调用上下文设置得很好。
但是,在等待 returns 之后,下面一行:
Message response = await SendRequestAsyncImpl(m, true).ConfigureAwait(false);
逻辑调用上下文为空。我想也许可以通过设置 ConfigureAwait(true) 而不是 false 来解决问题。但这并不能解决问题。
我尝试流什么都没有关系,甚至在 SendRequestAsyncImpl 中设置一个简单的值类型,如:
System.Runtime.Remoting.Messaging.CallContext.LogicalSetData("flag", true);
等待后无法检索。
为什么这在我的控制台应用程序中有效?但不是来自我的单元测试?有什么不同? (我已经看到了其他一些涉及 AppDomain 问题的堆栈溢出问题。但我什至无法在等待中编组 bool。编组数据的能力似乎不是这里的问题。)
因此,在阅读了 Stephen Clearly 在这个问题和文章中的评论之后:http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html 答案变得清晰了。
虽然在同步代码中,逻辑 CallContext 确实 流回方法。 在异步 方法中,CallContext 不会 流回。这是有道理的,因为 .NET 怎么知道我希望 CallContext 在 Task.WhenAll(...) 之类的东西之后如何合并。执行下面的代码说明:
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。由于上游和下游都获得了对同一个集合的引用,这 允许我通过在等待方法 [=36= 之后从集合 中检索它来将上下文从我等待的方法中向上流动].
希望这对以后的其他人有所帮助。
我正在使用 Logical CallContext 在一系列等待中回流信息。有趣的是,在我的测试控制台应用程序中,一切正常。但是,当 运行 我在 VS UnitTest 的上下文中进行单元测试时,调用上下文似乎没有流过等待。
方法内部:SendRequestAsyncImpl 正在设置调用上下文,当我在方法 returns 的那一刻从断点查询逻辑调用上下文时,调用上下文设置得很好。
但是,在等待 returns 之后,下面一行:
Message response = await SendRequestAsyncImpl(m, true).ConfigureAwait(false);
逻辑调用上下文为空。我想也许可以通过设置 ConfigureAwait(true) 而不是 false 来解决问题。但这并不能解决问题。
我尝试流什么都没有关系,甚至在 SendRequestAsyncImpl 中设置一个简单的值类型,如:
System.Runtime.Remoting.Messaging.CallContext.LogicalSetData("flag", true);
等待后无法检索。
为什么这在我的控制台应用程序中有效?但不是来自我的单元测试?有什么不同? (我已经看到了其他一些涉及 AppDomain 问题的堆栈溢出问题。但我什至无法在等待中编组 bool。编组数据的能力似乎不是这里的问题。)
因此,在阅读了 Stephen Clearly 在这个问题和文章中的评论之后:http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html 答案变得清晰了。
虽然在同步代码中,逻辑 CallContext 确实 流回方法。 在异步 方法中,CallContext 不会 流回。这是有道理的,因为 .NET 怎么知道我希望 CallContext 在 Task.WhenAll(...) 之类的东西之后如何合并。执行下面的代码说明:
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。由于上游和下游都获得了对同一个集合的引用,这 允许我通过在等待方法 [=36= 之后从集合 中检索它来将上下文从我等待的方法中向上流动].
希望这对以后的其他人有所帮助。