3

我正在尝试使用 Trace.CorrelationManager.ActivityId 来关联日志条目。但是,我发现这段代码何时完成:

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

ActivityId 与输入时的内容不同。虽然在 LongRunningMethod() 中它是正确的(我在方法中有各种跟踪事件),但它似乎只在等待完成时才会改变。

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

这行代码在一个用 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 方法?我基本上希望所有“LongRunningMethod”同时异步启动,然后等到全部完成。

4

2 回答 2

10

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

在 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

于 2013-12-31T16:30:33.237 回答
2

目前尚不清楚您为什么使用await关键字。如果您不需要“继续”所需任务,请使用

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

在调用await. await正在导致设置继续,它将使用不同的同步上下文运行,该同步上下文用于运行您LongRunningMethod()的将在后台线程池线程上运行。

我希望这有帮助。

于 2013-02-05T13:58:01.153 回答