【问题标题】:WCF Percall mode and threadstatic variablesWCF Percall 模式和线程静态变量
【发布时间】:2012-06-26 12:22:14
【问题描述】:

我们有多个 WCF 服务都使用 InstanceContextMode=PerCall 并且所有 WCF 服务实例都是通过使用 Unity (IOC) 和实现 IInstanceProvider 生成的。

关联标识符用于审计具有相同标识符的所有方法调用和数据库进程。

为了实现这一点,通过实现 IDispatchBehavior 来创建端点行为,并在 AfterReceiveRequest 方法中生成一个 guid 并将其分配给 ThreadStatic (CommonData) 属性。此属性可以在应用程序的所有层中访问。以下代码块显示了 CommonData 的填充以及 CommonData 类;

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            CommonData.ClearDictionary();
            //the lines between are deleted as they are not relevant to the question

            CommonData.Current.Add(MessageHeaderCodes.CorrelationId, Guid.NewGuid().ToString());    
            return null;
        }

和通用数据类:

public class CommonData
    {            
        [ThreadStatic]
        private static Dictionary<string, string> headerData;    

        public static Dictionary<string, string> Current
        {
            get
            {
                if (headerData == null)
                {
                    headerData = new Dictionary<string, string>();
                }
                return headerData;
            }            
        }

        private CommonData()
        {

        }

        public static string GetHeader(string header)
        {
            string headerValue = string.Empty;
            KeyValuePair<string, string> headerKeyValuePair = CommonData.Current.SingleOrDefault(p => p.Key == header);
            headerValue = headerKeyValuePair.Value;
            return headerValue;
        }

        public static void ClearDictionary()
        {
            Current.Clear();
        }
    }

这里的问题如下; 在某些服务中,开发人员报告相关标识符返回 null。由于问题是间歇性的,目前不可能有完整的堆栈跟踪。此外,他们表示重置 IIS 可以暂时解决此问题。

感谢任何帮助...

【问题讨论】:

  • 你究竟是如何检索标识符的(我猜是通过 GetHeader 方法)?
  • 我没有从客户端获取标识符,我只是在 AfterReceiveRequest 方法中为每个调用创建一个新标识符; CommonData.Current.Add(MessageHeaderCodes.CorrelationId, Guid.NewGuid().ToString());
  • 是的,但是您稍后会尝试以某种方式检索它,对吗?如何?如果不是 - 那么究竟什么是 null?
  • 这实际上是确切的问题:) 我创建了一个 guid,以便将所有正在运行的方法与数据库更改相关联。例如,如果调用了一个服务方法,则会生成一个带有生成 id 的日志;所有数据库更改也使用相同的 id。因此,可以将服务调用映射到方法调用和数据库更改。
  • 好吧,也许我明白了,但是你为什么需要字典。一个字符串值(每个线程)就足够了,不是吗?

标签: c# .net wcf c#-4.0


【解决方案1】:

这并不能真正回答您的问题,并且应该是一个评论,除非我想要一些代码......

我对您的 GetHeader 方法感到困惑。你为什么在字典上做一个 Linq .FirstOrDefault(),而不仅仅是:

public static string GetHeader(string header)
{
    if(CommonData.Current.ContainsKey(header))
        return CommonData.Current[header];
    return null;
}

除此之外,我实际上并没有发现您的代码有任何问题。我很好奇开发人员从哪里获得空标识符。他们当然必须确保他们在调用调度程序的同一线程上。如果在任何地方使用任何异步进程或 ThreadPool 在另一个线程上运行某些东西,则 [ThreadStatic] 将不存在。

我曾经遇到过一个问题,我(非常愚蠢地)从一个由终结器调用的方法中引用了我的 [ThreadStatic] 变量,该终结器在 GC 线程上运行,因此我的线程静态始终为空。哎呀:)

【讨论】:

  • 第一个或默认评论你是对的;我会更新,因为如果 headerKeyValuePair 为空可能会导致异常。开发人员在业务相关代码中获得空值。也许最好提供更多关于结构的细节,但我认为我只是错过了一些非常简单的东西。我会尝试更新问题...
【解决方案2】:

正如 Blam 建议的那样,我通过编写一个扩展来使用 OperationContext.Current 来存储自定义对象。以下是扩展名:

public class OperationContextExtension : IExtension<OperationContext>
{
    public void Attach(OperationContext owner)
    {
        this.Current = new Dictionary<string, string>();
    }

    public void Detach(OperationContext owner)
    {
        this.Current = null;
    }

    public Dictionary<string,string> Current { get; set; }
}

另一方面,我必须将 System.ServiceModel 引用添加到域对象。虽然这似乎不是一个正确的方式,因为域对象可以访问服务层,但它解决了我的问题。

【讨论】:

    【解决方案3】:

    几件事: 首先,您的 Threadstatic 值创建由 ThreadLocal 更好地实现。每当您需要初始化 threadstatic 字段时,基本上就是这种情况。使用

    private static ThreadStatic<Dictionary<string, string>> headerData = new ThreadStatic<Dictionary<string, string>>(() => new Dictionary<string, string>());
    

    其次,为了从字典中获取值,您要寻找的是 TryGetValue 方法。 IE。 not Contains-Get 对(因为它不需要两次哈希查找),当然也不是 SingleOrDefault。

    第三,要拥有一个可靠的 ID 来识别一次服务调用中发生的任何事情,只需将其作为所有后续方法调用的参数之一。

    【讨论】:

      猜你喜欢
      • 2013-03-29
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      相关资源
      最近更新 更多