考虑以下ASP.NET Web API委派处理程序:
public class MyHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var guid = Guid.NewGuid();
HttpContext.Current.Items["foo"] = guid;
// An Async operation
var result = await base.SendAsync(request, cancellationToken);
//All code from this point is not gauranteed to run on the same thread that started the handler
var restoredGuid = (Guid)HttpContext.Current.Items["foo"];
//Is this gauranteed to be true
var areTheSame = guid == restoredGuid;
return result;
}
}
以上示例位于委托处理程序中,我尝试修复的问题同样适用于控制器,业务对象等。
我最终试图在每个HTTP请求的各种对象之间提供一些简单的内存中共享状态
据我所知,在异步操作期间,最初运行该操作的ASP.NET线程将返回到线程池,并且在异步操作完成后可以使用不同的线程来完成请求。
这是否会影响HttpContext.Current.Items
集合?
请求恢复后,Items
集合中的项目是否保证在那里?
我知道使用HttpContext.Current
经常不赞成
由于我完全同意的原因,这些天来更广泛的社区
与...我只是帮助某人挤出一个果酱。
将此数据存储在Request.Items
集合中并不适合解决此问题,因为我的同事由于某些糟糕的设计决策而需要静态。
非常感谢
答案 0 :(得分:26)
据我所知,在异步操作期间,最初运行该操作的ASP.NET线程将返回到线程池,并且在异步操作完成后可以使用不同的线程来完成请求。
这是正确的。但是,让我们在ASP.NET上讨论async
一分钟。
async
需要.NET 4.5。此外,ASP.NET 4.5在服务器端引入了“怪癖模式”,您必须关闭SynchronizationContext
quirk 。您可以使用httpRuntime.targetFramework
4.5
appSettings
来设置aspnet:UseTaskFriendlySynchronizationContext
至true
或。
如果您的web.config没有其中一个条目,则async
的行为未定义。有关详细信息,请参阅this post。我建议使用targetFramework
设置并修复出现的任何问题。
这会影响HttpContext.Current.Items集合吗?当请求恢复时,Items集合中的项目是否保证在那里?
AspNetSynchronizationContext
在await
点之间保留当前请求上下文。其中包括HttpContext.Current
(包括Items
,User
等)。
另一种可能性是CallContext.Logical[Get|Set]Data
,它也会流过await
个点。如果您不希望HttpContext
上存在代码依赖性,但是开销略有增加,那么这很有用。
几周前我在ThatConference上发表了一篇关于async
on the server side的演讲。您可能会发现幻灯片很有用,特别是那些处理Context和Thread-Local State的幻灯片。
答案 1 :(得分:5)
长话短说,通常应该。除非您使用的ConfigureAwait(false)
可能会产生副作用,并且不会延续上下文。
或者尝试在您的应用中添加此设置。
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
请注意! 最初我把假。但它必须 true 才能使上下文流动。