我有一个使用在IIS中运行的WCF REST的ASP.NET应用程序。
我需要存储当前HTTP请求的变量,我使用HttpContext.Current.Items
。我存储了我在global.asax
中设置的一些请求ID,因此我可以在我的服务中更深入地使用它。我的服务正在进行一些I / O操作,所以我最近将它们从同步更改为异步。问题出在第一个await
之后,HttpContext.Current
变为空,因此我无法访问存储在HttpContext.Current.Items
中的变量。
我的global.asax:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Items["CurrentRequestId"] = SetRequestId();
}
我的WCF合同:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WcfService
{
[OperationContract]
[WebGet(UriTemplate = "Operation")]
public async Task<bool> Operation()
{
var context = HttpContext.Current; // Current context available here
await Task.Delay(1000).ConfigureAwait(true); // tried with both ConfigureAwait(true) and ConfigureAwait(false)
context = HttpContext.Current; // Current context is always null here
return true;
}
}
我尝试在我的web.config文件中添加这些键,但它没有改变任何内容。
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
<add key="wcf:disableOperationContextAsyncFlow" value="false"/>
</appSettings>
我正在使用.net 4.6.2
<httpRuntime targetFramework="4.6.2" />
在使用ASP.NET的WCF REST中等待异步方法之后是否可以保留HttpContext.Current
?是否有HttpContext.Current.Items
替代我可以用来实现我想做的事情?
编辑:这是一个简化的示例,但HttpContext.Current
的使用方式更深,我宁愿不必在等待之前收集它并将其一直传递到每个单一方法。
答案 0 :(得分:1)
这个问题实际上与异步代码无关;它与从(非请求)线程池线程中检索上下文变量有关。
链接博客中推荐的技术(包装HttpContext并将其提供给工作线程)非常危险。 HttpContext被设计为一次只能从一个线程访问,而AFAIK根本不是线程安全的。因此,在不同的线程之间分享它是一个受伤的世界。
所以我强烈建议您在异步方法之前从HttpContext中获取所需的所有内容,然后再使用它。
答案 1 :(得分:0)
我在WCF中遇到过类似的问题,在等待任务后我丢失了OperationContext。实际上在等待之后 - 从线程池分配的线程没有上下文(基本上是一个不同的线程)。我们创建了一个通用的包装器方法来处理这个问题。下面我尝试在你的问题的上下文中转换相同的。试试吧:
.btn.active {
background-color: limegreen;
}
大卫关于线程安全的观点 - 我考虑过它并做了一些尽职调查以确保线程安全。