2012-06-26 53 views
0

我們有多個WCF服務,都使用InstanceContextMode = PerCall,並且所有WCF服務實例都是通過使用Unity(IOC)並實現IInstanceProvider來生成的。WCF Percall模式和線程靜態變量

相關標識符用於審覈具有相同標識符的所有方法調用和數據庫進程。

爲了實現此目的,通過實現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

你究竟如何檢索標識符(我猜GetHeader方法)? – Bond

+0

我沒有從客戶端獲取標識符,我只是在AfterReceiveRequest方法中爲每個調用創建一個新的標識符; CommonData.Current.Add(MessageHeaderCodes.CorrelationId,Guid.NewGuid()。ToString()); – daryal

+0

是的,但你嘗試稍後以某種方式檢索它?怎麼樣?如果不是 - 那麼究竟什麼是空的? – Bond

回答

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引用添加到域對象。儘管由於域對象可以訪問服務層,它看起來並不合適,但它解決了我的問題。

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線程上運行調用的方法,所以我的線程靜態總是爲空。哎呀:)

+0

您對第一條或第三條錯誤評論是正確的;我會更新,因爲如果headerKeyValuePair爲null,可能會導致異常。開發人員在與業務相關的代碼中獲得空值。也許最好提供更多有關結構的細節,但我認爲我只是錯過了一些非常簡單的東西。我會嘗試更新問題... – daryal

1

幾件事情: 首先,您的Threadstatic值創建最好由ThreadLocal實現。基本上就是這樣,只要你需要你的線程靜態字段被初始化。使用

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

其次,爲了從字典中獲取值,您要查找的是TryGetValue方法。即不包含 - 獲取對(因爲它不需要兩次散列查找),當然不是SingleOrDefault。

第三,要有一個可靠的ID來標識從一個服務調用發生的任何事情,只需將其作爲所有後續方法調用的參數之一。