在哪里存储当前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。 用达林的方法来代替。 正如@ np-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之外传播。