简体   繁体   English

WCF Percall模式和threadstatic变量

[英]WCF Percall mode and threadstatic variables

We have multiple WCF services all working with InstanceContextMode=PerCall and all WCF service instances are generated by employing Unity (IOC) and implementing IInstanceProvider. 我们有多个WCF服务都使用InstanceContextMode = PerCall,所有WCF服务实例都是通过使用Unity(IOC)和实现IInstanceProvider生成的。

A correlation identifier is used to audit all method calls and database processes with the same identifier. 相关标识符用于审计具有相同标识符的所有方法调用和数据库进程。

In order to achieve this, an endpoint behavior is created by implementing IDispatchBehavior and in AfterReceiveRequest method, a guid is generated and assigned to a ThreadStatic ( CommonData ) property. 为了实现这一点,通过实现IDispatchBehavior创建端点行为,并在AfterReceiveRequest方法中生成guid并将其分配给ThreadStatic( CommonData )属性。 This property can be access in all layers of the application. 可以在应用程序的所有层中访问此属性。 The following code block shows the population of CommonData, and the CommonData class; 以下代码块显示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;
        }

and commondata class: 和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();
        }
    }

The problem here is the following; 这里的问题如下: In some of the services, developers reported that the correlation identifier returns null. 在某些服务中,开发人员报告相关标识符返回null。 Since the problem is intermittant it is not possible to have a full stack trace at the moment. 由于问题是间歇性的,因此目前不可能有完整的堆栈跟踪。 Also, they stated that reseting IIS resolves this problem temporarily. 此外,他们表示重置IIS会暂时解决此问题。

Any help is appreciated... 任何帮助表示赞赏......

This doesn't really answer your question, and would have been a comment, except I wanted to have some code... 这并没有真正回答你的问题,而且本来是评论,除了我想要一些代码......

I am confused by your GetHeader method. 我对你的GetHeader方法感到困惑。 Why are you doing a Linq .FirstOrDefault() on the dictionary, instead of just: 你为什么要在字典上做一个Linq .FirstOrDefault() ,而不仅仅是:

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

Aside from that, I don't actually see anything wrong with your code. 除此之外,我实际上并没有发现你的代码有任何问题。 I am curious as to where the developers are getting the null identifier. 我很好奇开发人员在哪里获得空标识符。 They would of course have to make sure they are on the same thread that the dispatcher was called on. 他们当然必须确保它们与调度员被调用的线程相同。 If any async process, or ThreadPool was used anywhere to run something on another thread, then the [ThreadStatic] would not exist. 如果在任何地方使用任何异步进程或ThreadPool在另一个线程上运行某些东西,则[ThreadStatic]将不存在。

I had an issue once where I (very stupidly) referenced my [ThreadStatic] variable from a method that was called by a finalizer, which is run on the GC thread, so my thread static was always null. 我有一个问题,我(非常愚蠢地)从一个终结器调用的方法引用我的[ThreadStatic]变量,该方法在GC线程上运行,因此我的线程静态始终为null。 oops :) 哎呀:)

As Blam suggested, I have employed OperationContext.Current by writing an Extension to store custom objects. 正如Blam建议的那样,我通过编写扩展来存储自定义对象,从而使用了OperationContext.Current。 Below is the extension: 以下是扩展名:

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; }
}

On the otherhand, I have to add System.ServiceModel reference to the domain objects. 另一方面,我必须将System.ServiceModel引用添加到域对象。 Although it does not seem to be a proper way as domain objects can access to the service layer, it resolved my problem. 虽然它似乎不是一种正确的方式,因为域对象可以访问服务层,但它解决了我的问题。

Several things: First, Your Threadstatic value creation is better implemented by ThreadLocal. 以下几点:首先,ThreadLocal可以更好地实现Threadstatic值的创建。 This is basically the case whenever you need your threadstatic field to be initialized. 无论何时需要初始化threadstatic字段,基本上都是这种情况。 Use 采用

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

Second, for acquiring the value from the dictionary, what you're looking for is the TryGetValue method. 其次,为了从字典中获取值,您正在寻找的是TryGetValue方法。 Ie not Contains-Get pair (as it does hash lookup twice unnecessary), and certainly not SingleOrDefault. 即不包含 - 获取对(因为它不需要两次哈希查找),当然不是SingleOrDefault。

And third, to have a reliable ID identifying whatever happened from the one service call, just have it as one of the parameters of all the subsequent method calls. 第三,要有一个可靠的ID来识别从一个服务调用发生的事情,只需将它作为所有后续方法调用的参数之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM