1

在同步环境中,很容易创建一个作用域上下文,它允许您将带外上下文附加到当前线程。这方面的示例是当前的 TransactionScope 或线程静态日志记录上下文。

using (new MyContext(5))
    Assert.Equal(5, MyContext.Current);

Assert.Equal(null, MyContext.Current);

使用IDisposable 和线程静态字段的组合很容易实现上下文。

显然,这在使用异步方法时会分崩离析,因为上下文是基于线程静态字段的。所以,这失败了:

using (new MyContext(5))
{
    Assert.Equal(5, MyContext.Current);

    await DoSomethingAsync();

    Assert.Equal(5, MyContext.Current);
}

当然,我们还希望将上下文传递给调用链中的异步方法,所以这应该也可以:

using (new MyContext(5))
{
    Assert.Equal(5, MyContext.Current);

    await AssertContextIs(5);
}

有谁知道如何实施?在使用 async/await 模式时丢失带外上下文会使某些代码片段非常难看。

考虑一下您希望使用基于请求的上下文进行日志记录的异步 WebAPI 调用。您希望调用堆栈深处的记录器知道请求 ID,而无需使用参数将请求 ID 一直传递到调用堆栈。

谢谢你的帮助!

4

2 回答 2

5

最好的解决方案是HttpContext.Current.Items在 ASP.NET 或IOwinRequest.[Get|Set]OWIN 中使用。是的,这确实意味着将请求对象传递到任何地方,如果您认为您的“上下文值”属于该请求,这是有道理的。如果您对了解 OWIN 的“库”方法感到不舒服,那么很容易编写一个“上下文包装器”对象并传递它。

但是,如果您确定不想传递任何东西,那么您可以使用LogicalCallContext我在博客中描述的不可变数据。如果您只关心日志记录,那么您可能会发现我的AsyncDiagnostics 库很有用 - 它使用 PostSharp 注入方法名称,您也可以将自己的信息添加到“异步堆栈”中。

于 2014-09-24T14:38:53.443 回答
0

如果您在托管环境中(您正在谈论 WebAPI),您应该使用请求上下文(HttpContext.Current),而不是线程,因为您不管理线程并且不知道原始线程何时/是否可用也没有如何恢复它。

使用await关键字正确处理请求上下文。

于 2014-09-24T09:36:16.553 回答