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

Posted

技术标签:

【中文标题】在哪里存储当前 WCF 调用的数据? ThreadStatic 安全吗?【英文标题】:Where to store data for current WCF call? Is ThreadStatic safe? 【发布时间】:2010-12-26 03:04:01 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

有一个博客post 建议实施IExtension<T>。你也可以看看这个discussion。

这是一个建议的实现:

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;

【讨论】:

谢谢,我会研究这个选项。 @Darin:看看我提供的另一个答案,你怎么看? 应该是 'WcfOperationContext' 而不是 'WcfInstanceContext'? 第一个链接已失效 :( 对于 .Net 4.5+,是否推荐使用此方法而不是 CallContext.LogicalGetData、CallContext.LogicalSetData?【参考方案2】:

无需添加额外驱动类的替代解决方案。

    OperationContext operationContext = OperationContext.Current;
    operationContext.IncomingMessageProperties.Add("SessionKey", "ABCDEFG");

获取价值

var ccc = aaa.IncomingMessageProperties["SessionKey"];

就是这样

【讨论】:

【参考方案3】:

我发现当我们使用多线程切换进行异步调用时,我们会丢失数据或当前上下文。要处理这种情况,您可以尝试使用 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 之外。

【讨论】:

这是遗留技术,official documentation 已存档并明确提及:This topic is specific to a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using the Windows Communication Foundation (WCF).

以上是关于在哪里存储当前 WCF 调用的数据? ThreadStatic 安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.Net WCF 服务的 Thread.CurrentPrincipal 被联邦 (WIF) 环境中的某些拦截器丢弃

Wcf 事务和 SQL 存储过程

WCF服务中的wsdl文件在哪里

WCF 和 ADO.Net 数据服务在哪里?

从 WCF 服务如何以当前用户而不是 IIS\DefaultApppool 的身份调用第三方 dll 中的方法

在 WCF REST 服务中调用 WebGet 时出错