24

尝试使用新的 C# 5 异步模型令我惊讶的AspNetSynchronizationContext是一个内部类(以及AspNetSynchronizationContextBase基类)。因此无证。但是在您的 ASP.NET 代码中使用 async/await 功能时,了解它的作用很重要。我是否正确,它确实保证您的延续将与HttpContext.Current原始呼叫者相同?它保证延续将在与调用者相同的线程上执行?

如果后一个假设不正确并且我得到了原始线程,我可以确保在延续中获得相同的线程上下文吗?我的意思是与线程和线程本地存储相关的主体/文化?这很重要,因为 ASP.NET 本地化依赖于线程的文化,而我的应用程序依赖于 .NET 角色安全模型(线程的主体)。

4

2 回答 2

28

我是否正确它确实保证您的延续将获得与原始调用者相同的 HttpContext.Current ?它不保证延续将在与调用者相同的线程上执行?

是的,HttpContext.Current被保留了,是的,延续可能在不同的线程上执行。

我的意思是与线程和线程本地存储相关的主体/文化?这很重要,因为 ASP.NET 本地化依赖于线程的文化,而我的应用程序依赖于 .NET 角色安全模型(线程的主体)。

普通线程本地存储丢失。您可以通过使用LogicalCallContext(与 一起流动ExecutionContext)来缓解这种情况,但async直接引用变量会更容易。

本金始终保留;否则会带来安全风险。这与ExecutionContext.

我相信文化会随着.NET 4.5 的新实现AspNetSynchronizationContext而流动,但我还没有对此进行测试。


您可能会发现我的MSDN 文章SynchronizationContext很有帮助。它不是官方文档(我不为微软工作),但至少它是一些东西。请注意,该AspNetSynchronizationContext文章中引用的内容现在LegacyAspNetSynchronizationContext在 .NET 4.5 中调用。

另一个很好的资源是 Stephen Toub 的ExecutionContextvs.SynchronizationContext .

于 2012-09-30T12:28:05.983 回答
6

好吧,虽然总是保证捕获 ExecutionContext,但在同一个 SynchronizationContext 上捕获和运行执行取决于 Awaiter。

最常见的等待器(当您“等待”某物时在内部调用的 GetAwaiter() 方法返回的类型)是由 Task.GetAwaiter() 返回的 TaskAwaiter。默认情况下,TaskAwaiter将捕获当前 SynchronizationContext 并在捕获的 SynchronizationContext 上运行延续委托。这意味着,您将能够在方法的其余部分中使用 HttpContext.Current,并且您不介意它将作为延续运行。因此,此代码将按预期工作(您编写“B”的部分将在与第一行相同的同步上下文中运行):

HttpContext.Current.Response.Write("A");
await Task.Delay(1000);
HttpContext.Current.Response.Write("B")

您可以通过使用更改此行为Task.ConfigureAwait(false)方法告诉等待者不要将方法的其余部分编组回原始 SynchronizationContext。

当然,如果您在调用的异步方法中使用 Task.Run 或 Task.Factory.StartNew,那么您有责任再次捕获 SynchronizationContext。

祝你好运。

于 2012-09-30T09:28:33.633 回答