我们有多个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会暂时解决此问题。
感谢任何帮助...
答案 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线程上运行,因此我的线程静态始终为null。哎呀:)
答案 1 :(得分: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引用。虽然它似乎不是一种正确的方式,因为域对象可以访问服务层,但它解决了我的问题。
答案 2 :(得分:1)
有几件事: 首先,ThreadLocal可以更好地实现Threadstatic值的创建。无论何时需要初始化threadstatic字段,基本上都是这种情况。使用
private static ThreadStatic<Dictionary<string, string>> headerData = new ThreadStatic<Dictionary<string, string>>(() => new Dictionary<string, string>());
其次,要从字典中获取值,您要查找的是TryGetValue方法。即不包含 - 获取对(因为它不需要两次哈希查找),当然也不是SingleOrDefault。
第三,要有一个可靠的ID来识别从一个服务调用发生的事情,只需将它作为所有后续方法调用的参数之一。