在哪里存储当前WCF调用的数据? ThreadStatic是安全的吗?

当我的服务执行时,许多类将需要访问User.Current(这是我自己的用户类)。 我可以安全地将_currentUser存储在[ThreadStatic]variables中吗? WCF是否重用其线程? 如果是这样,什么时候清理ThreadStatic数据? 如果使用ThreadStatic是不安全的,我应该在哪里放置数据? 在OperationContext.Current里面有一个地方可以存储那种数据吗?

编辑12/14/2009:我可以断言,使用ThreadStaticvariables是不安全的。 WCF线程位于线程池中,并且ThreadStaticvariables不会重新初始化。

有一个博客文章 ,build议实施IExtension<T> 。 你也可以看看这个讨论 。

这是一个build议的实现:

 public class WcfOperationContext : IExtension<OperationContext> { private readonly IDictionary<string, object> items; private WcfOperationContext() { items = new Dictionary<string, object>(); } public IDictionary<string, object> Items { get { return items; } } public static WcfOperationContext Current { get { WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>(); if (context == null) { context = new WcfOperationContext(); OperationContext.Current.Extensions.Add(context); } return context; } } public void Attach(OperationContext owner) { } public void Detach(OperationContext owner) { } } 

你可以这样使用:

 WcfOperationContext.Current.Items["user"] = _currentUser; var user = WcfOperationContext.Current.Items["user"] as MyUser; 

编辑:不要使用这个解决scheme。 用达林的方法来代替。 正如@ n​​p-hard所说,如果存在asynchronous操作(线程切换发生),则此解决scheme不起作用。


我find了另外一个解决 你可以使用OperationContext类的OperationCompleted事件清除你的ThreadStaticvariables。

 public class SomeClass { [ThreadStatic] private static _currentUser = null; public static void GetUser() { if ( _currentUser == null ) { _currentUser = LoadUser(); // Reinitialize _currentUser at the end of the request OperationContext.Current.OperationCompleted += (sender, args) => _currentUser = null; } return _currentUser; } } 

当我们使用multithreading切换进行asynchronous调用时,我发现我们错过了数据或当前上下文。 为了处理这种情况,你可以尝试使用CallContext。 它应该在.NET远程处理中使用,但它也应该在这种情况下工作。

在CallContext中设置数据:

 DataObject data = new DataObject() { RequestId = "1234" }; CallContext.SetData("DataSet", data); 

从CallContext中检索共享数据:

 var data = CallContext.GetData("DataSet") as DataObject; // Shared data object has to implement ILogicalThreadAffinative public class DataObject : ILogicalThreadAffinative { public string Message { get; set; } public string Status { get; set; } } 

为什么ILogicalThreadAffinative?

当对另一个AppDomain中的对象进行远程方法调用时,当前的CallContext类将生成一个LogicalCallContext,并随调用一起传输到远程位置。

只有公开ILogicalThreadAffinative接口并存储在CallContext中的对象才会在AppDomain之外传播。