使用HttpContext.Current.Session时WCF服务并行请求失效的解决办法咨询
这问题我之前也碰到过——当你在WCF服务里用上System.Web.HttpContext.Current.Session后,原本正常的并行请求突然变成串行,核心原因和ASP.NET Session的独占锁机制有关,再加上WCF的默认实例模式加成,直接把并行路给堵死了。下面给你拆解原因和可行的解决方案:
为什么会出现这个问题?
当你启用ASP.NET兼容模式(用HttpContext.Current.Session就必须开这个),ASP.NET的Session默认是可写状态,此时同一个SessionID的所有请求会被ASP.NET强制串行处理——它会给Session加独占锁,直到请求处理完才释放,自然没法并行。另外,WCF默认的InstanceContextMode.PerSession实例模式也会让同一个会话的请求绑定到同一个服务实例,进一步限制了并发能力。
解决方案分两种情况:
情况1:只需要读取Session,不需要写入
这种情况最简单,把Session设置为只读模式,ASP.NET就会允许同一个Session的请求并行处理,不会加独占锁。
具体配置步骤:
- 确保WCF启用了ASP.NET兼容模式:
- 在Web.config的
<system.serviceModel>节点下添加:<serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> - 在你的服务类上添加特性:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] public class YourWcfService : IYourWcfService { // 你的服务实现 }
- 在Web.config的
- 把Session设置为只读:
在Web.config的<system.web>节点下修改sessionState配置:
这样设置后,你依然可以读取<sessionState mode="InProc" readOnly="true" />Session["UserName"]这类数据,但不能修改;如果你的代码里有写入Session的操作,会直接抛出异常,所以要确保所有Session操作都是只读的。
情况2:必须要写入Session
这时候ASP.NET的独占锁机制是绕不开的——因为并发写入Session会导致数据冲突,所以ASP.NET本身就不允许这种情况。这时候你得换个思路:
- 放弃ASP.NET Session,改用WCF自带的会话机制:WCF有自己的Session(和ASP.NET Session不是一回事),可以通过
OperationContext.Current.SessionId标识会话,然后把数据存储在服务实例里(如果用InstanceContextMode.PerSession),或者用外部存储(比如MemoryCache)关联SessionId来存数据。 - 改用分布式缓存存储会话数据:比如用
System.Runtime.Caching.MemoryCache或者第三方缓存(如Redis),把原本存在Session里的数据放到缓存中,用自定义的会话ID作为键,这样每个请求可以独立读写缓存,不会被ASP.NET的Session锁限制。 - 调整WCF实例和并发模式:设置
InstanceContextMode.PerCall(每个请求创建一个服务实例)和ConcurrencyMode.Multiple(允许实例同时处理多个请求),但这个前提是你不再依赖ASP.NET Session,因为PerCall模式下每个请求的上下文是独立的,ASP.NET Session的共享意义不大。
举个改用MemoryCache的例子:
public class YourWcfService : IYourWcfService { public void SetUserName(string sessionId, string userName) { MemoryCache.Default.Set(sessionId + "_UserName", userName, DateTimeOffset.Now.AddHours(1)); } public string GetUserName(string sessionId) { return MemoryCache.Default.Get(sessionId + "_UserName") as string; } }
这里的sessionId可以由客户端生成并传递,或者用WCF的OperationContext.Current.SessionId。
总结
如果只是读Session,开只读模式就能解决并行问题;如果必须写Session,就得换掉ASP.NET Session这个依赖,改用其他存储方式。毕竟ASP.NET Session的设计初衷就不是为高并发场景准备的。
内容的提问来源于stack exchange,提问作者Dharmesh Hadiyal

