1

我们有多个 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;
        }

和 commondata 类:

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 可以暂时解决此问题。

任何帮助表示赞赏...

4

3 回答 3

1

这并不能真正回答您的问题,并且会成为评论,除非我想要一些代码...

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

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

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

有一次我(非常愚蠢地)[ThreadStatic]从一个由终结器调用的方法中引用了我的变量,该方法在 GC 线程上运行,所以我的线程静态始终为空。哎呀:)

于 2012-06-26T12:57:13.563 回答
1

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

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

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

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

于 2012-09-12T13:50:21.337 回答
1

正如 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 引用。虽然它似乎不是一个正确的方式,因为域对象可以访问服务层,但它解决了我的问题。

于 2012-07-07T10:49:09.340 回答