2013-02-05 30 views
2

我想使用Trace.CorrelationManager.ActivityId关联日志条目。但是,当代码结束时,我发现:await Task.Run退出跟踪ActivityId退出

var result = await Task.Run(() => LongRunningMethod()); 

ActivityId从它进入时的状态发生了变化。在LongRunningMethod()中,它是正确的(我在该方法中有各种跟踪事件),它只在await完成时才会改变。

我的问题是为什么ActivityId改变了?

这行代码与异步声明的函数,这又通过在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 
} 

也许我现在用的是异步/坐等或工作方法不当?我基本上希望所有'LongRunningMethod'异步启动,然后等到所有完成。

+0

什么问题? – svick

+0

你使用.NET 4.5吗? –

+0

问题是ActivityId为什么会改变。 是的,使用.NET 4.5 – user380689

回答

1

目前尚不清楚您为什么使用await关键字。如果您不需要所需的任务的“延续”,通过启动

var result = Task.Factory.StartNew(() => LongRunningMethod()); 

很可能(但不能保证因为你给的代码量小),您的电话后有代码awaitawait正在导致设置的延续,该运行将使用用于运行将在后台线程池线程上运行的LongRunningMethod()的不同同步上下文运行。

我希望这会有所帮助。

9

你没有做错,但它不会工作。

在WCF和ASP.NET(包括MVC)下,在框架执行请求之前,它捕获当前上下文,以便它可以恢复它以确保完成在原始线程上运行。

不幸的是,这发生在您的控制器被调用之前。系统的快照发生在您有机会更新ActivityID之前。继续,在设置它之前,上下文重置为该值。

我发现如果您向任务添加.ConfigureAwait(false),则不必在原始上下文上运行延续,因此您的活动ID将被恢复。

目前我还没有更好的解决方案,除了使用CallContext.LogicalGetData/LogicalSetData来管理你自己的ActivityID之外。对于我在EventSourceProxy中处理它的方式,请参阅https://github.com/jonwagner/EventSourceProxy/commit/fa43c6acd07690dcd276346e3fcf25028f796b8c

下面是一个更深入的解释。

http://sticklebackplastic.com/post/2007/08/14/One-mighty-gotcha-for-SystemDiagnostic-activity-Ids.aspx

+0

你说这个行为是特定于ASP.NET/WCF吗? – Kakira

+0

我不认为它是特定于ASP/WCF。我没有看过框架代码,但我想这个问题是在ThreadPool的某个地方。 –