【问题标题】:AspNetSynchronizationContextAspNetSynchronizationContext
【发布时间】:2012-09-21 12:14:08
【问题描述】:

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

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

【问题讨论】:

  • 我所知道的是,当你在等待调用后恢复时,无论你得到什么线程,它的“名称”都会重置为空。一旦它回到游泳池,它就会被清除。至于与线程相关的其他属性......我不知道。

标签: asp.net .net asynchronous async-await c#-5.0


【解决方案1】:

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

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

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

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

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

我相信文化会随着AspNetSynchronizationContext 而流动,但我还没有在.NET 4.5's new implementation 上测试过。


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

另一个很棒的资源是 Stephen Toub 的ExecutionContext vs. SynchronizationContext

【讨论】:

  • 很好的答案!正是我想听到的加上一些有用的链接。非常感谢!
  • 我假设AspNetSynchronizationContextThread.CurrentPrincipal 的行为有点奇怪:stackoverflow.com/a/12030785/463785 你知道这是AspNetSynchronizationContext 还是其他一些深层ASP 的错。 NET 的东西?
  • 我不能肯定。核心 .NET 上下文 (ExecutionContext) 可能对 CurrentPrincipal 有一些特殊规则(出于安全原因),而 ASP.NET 无法克服这一点(例如,在部分信任的情况下)。但这只是猜测。
【解决方案2】:

好吧,虽然总是保证捕获 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。

祝你好运。

【讨论】:

  • 是的,但我认为这不是问题所在。如果您确实捕获上下文,它会询问 ASP.NET 中具体发生了什么。
  • 那么当然,你拥有一切......这就是上下文的定义。它适用于 ExecutionContext(无论如何都被捕获)和 SynchronizationContext(它实际上是 ExecutionContext 的一部分,但它可以被捕获也不能被捕获)。
猜你喜欢
  • 2014-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多