我正在尝试使用Trace.CorrelationManager.ActivityId来关联日志条目。但是,我发现此代码何时完成:
var result = await Task.Run(() => LongRunningMethod());
ActivityId已经从输入时改变了。在LongRunningMethod()中它是正确的(我在方法中有各种跟踪事件),它似乎只在await完成时改变。
我的问题是为什么ActivityId会改变?
这行代码位于使用async声明的函数中,而async又由MVC项目中的异步控制器操作调用:
async public Task<ActionResult> Index()
{
...
var tasks = {list of Download<T> delegates}
var result = await Task.WhenAll(tasks)
}
async public Task<OperationResult> Download<T>(IEnumerable<T> data, Device device)
{
...
var result = await Task.Run(() => LongRunningMethod());
return result
}
也许我错误地使用async / await或Task方法?我基本上都想要所有的&#39; LongRunningMethod&#39;同时以异步方式启动,然后等到所有结束。
答案 0 :(得分:10)
你做错了,但是不行。
在WCF和ASP.NET(包括MVC)下,在框架执行请求之前,它会捕获当前上下文,因此可以恢复它以确保完成在原始线程上运行。
不幸的是,这会在您的控制器被调用之前发生。系统的快照发生在您有机会更新ActivityID之前。在继续中,上下文将重置为您设置之前的值。
我发现如果你将.ConfigureAwait(false)添加到你的任务中,那么继续不必在原始上下文上运行,所以你的活动ID将被恢复。
我目前没有更好的解决方案,除了使用CallContext.LogicalGetData / LogicalSetData来管理自己的ActivityID。对于我在EventSourceProxy中处理它的方式,请参阅https://github.com/jonwagner/EventSourceProxy/commit/fa43c6acd07690dcd276346e3fcf25028f796b8c
这是一个更深入解释的精彩文章。
答案 1 :(得分:1)
目前尚不清楚您使用await
关键字的原因。如果您不需要“继续”所需任务,请使用
var result = Task.Factory.StartNew(() => LongRunningMethod());
在调用await
之后,您可能会(但由于您提供的代码量很少而无法保证)您拥有代码。 await
导致继续设置,将使用不同的同步上下文运行,该同步上下文用于运行将在后台线程池线程上运行的LongRunningMethod()
。
我希望这会有所帮助。