gpt4 book ai didi

asp.net-mvc-3 - 通过 ASP.NET 同步上下文安全地执行任务,无需 AsyncManager.Sync

转载 作者:行者123 更新时间:2023-12-02 14:13:03 26 4
gpt4 key购买 nike

我正在尝试将 AsyncController 与依赖注入(inject)混合在一起。相关 MVC 应用程序几乎通过异步 Web 服务调用获取其所有数据。我们将异步工作包装在来自 TPL 的任务中,并在这些任务完成时通知 Controller 的 AsyncManager。

有时我们必须在这些任务的继续过程中接触 HttpContext - 添加 cookie,等等。根据 Using an Asynchronous Controller in ASP.NET MVC 执行此操作的正确方法就是调用AsyncManager.Sync方法。这会将 ASP.NET 线程上下文(包括 HttpContext)传播到当前线程,执行回调,然后恢复之前的上下文。

但是,那篇文章还说:

Calling Sync() from a thread that is already under the control of ASP.NET has undefined behavior.

如果您在 Controller 中完成所有工作,这不是问题,因为您通常知道在延续中应该位于哪个线程上。但我想做的是在异步数据访问和异步 Controller 之间创建一个中间层。所以这些也是异步的。一切都通过 DI 容器连接起来。

与之前一样,调用链中的某些组件需要使用“当前”HttpContext。例如,登录后我们想要存储从单点登录服务返回的“ session ” token 。执行此操作的抽象是 ISessionStore。想象一下 CookieSessionStore 将 cookie 放在响应中,或从请求中获取 cookie。

我可以看到两个问题:

  1. 这些组件无权访问 AsyncManager,甚至不知道它们正在 Controller 中使用。
  2. 组件不知道它们是从哪个线程调用的,因此 AsyncManager.Sync 或任何等效项在理论上无论如何都是有问题的。

为了解决#1,我基本上注入(inject)一个对象,该对象在请求开始时抓取 TaskScheduler.FromCurrentSynchronizationContext() ,并且可以通过从该调度程序启动的任务调用操作,采取HttpContextBase 作为参数。

也就是说,从我的组件中,我可以调用类似的内容:

MySyncObject.Sync(httpContext => /* Add a cookie or something else */);

我还没有发现任何问题,但我担心问题#2。我查看了 Reflector 中的 AsyncManagerSynchronizationContextTaskScheduler,它们的操作类似,在 ASP.NET SynchronizationContext 上执行回调。这让我害怕:)

当我看到任务调度程序实现将直接调用而不是通过同步上下文(如果它是内联)时,我有一点希望。但不幸的是,这似乎不会通过正常的 Task.Start(scheduler) 代码路径发生。相反,任务可以在其他情况下内联,例如在开始之前等待它们。

所以我的问题是:

  1. 采用这种方法我会遇到麻烦吗?
  2. 有更好的方法吗?
  3. 在这种情况下同步的用处仅仅是序列化对非线程安全的 HttpContext 的访问吗?即我可以使用线程安全的 HttpContextBase 包装器来代替(ick)吗?

最佳答案

依赖线程本地静态很少是一个好主意。虽然 HttpContext.Current 依赖于该机制并且它已经工作了多年,但现在我们要异步了,这种方法正在迅速恶化。最好将这个静态值捕获为局部变量,并将其与异步工作一起传递,以便您始终拥有它。因此,例如:

public async Task<ActionResult> MyAction() {
var context = HttpContext.Current;
await Task.Yield();
var item = context.Items["something"];
await Task.Yield();
return new EmptyResult();
}

或者更好的是,如果您使用 MVC,请完全避免使用 HttpContext.Current:

public async Task<ActionResult> MyAction() {
await Task.Yield();
var item = this.HttpContext.Items["something"];
await Task.Yield();
return new EmptyResult();
}

可以说,您的中间件业务逻辑尤其不应该依赖于 HttpContext 或 ASP.NET 库中的其他任何内容。因此,假设您的中间件回调 Controller (通过回调、接口(interface)等)来设置 cookie,那么您将可以使用 this.HttpContext 来访问该上下文。

关于asp.net-mvc-3 - 通过 ASP.NET 同步上下文安全地执行任务,无需 AsyncManager.Sync,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11264417/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com