2013-05-01 44 views
2

我有一個wcf服務(託管在IIS中),是setup to use sessions。它似乎工作。當調用Application_PostAcquireRequestState時,我有一個會話ID。WCF是否在多個線程上運行會話?

我最終使用它像這樣(在我的Global.asax):

if (Context.Handler is IRequiresSessionState) 
{ 
    log4net.ThreadContext.Properties["sessionId"] = Session.SessionID; 
} 

這似乎很好地工作。該值存儲在我的log4net屬性中。

但是當我的服務操作開始時(我的實際WCF服務代碼),log4net屬性再次爲空。

由於該屬性是按線程(ThreadContext)存儲的,我只能假設這意味着會話在一個線程上設置,然後在另一個線程上執行。我對嗎?

有沒有辦法讓我的log4net屬性設置在正確的線程上(而不必記住在每個服務操作開始時進行上述調用)?

+0

我總是期望涉及多個線程。我不確定我是在哪裏選擇的。您是否在自己的服務中尋找(定製)行爲來實現您想要的? – rene 2013-05-01 14:28:20

回答

1

有多種場景中WCF可能會改變你的線程:

  1. 不保證該Global.asx線程用於服務電話(其實它不太可能)。
  2. 如果在同一會話期間有多個呼叫,線程也可能在對相同服務實例的呼叫之間改變。

理論上這樣的狀態信息應該存儲在Operation Context對象中。但是,因爲log4net使用線程本地存儲,它成爲一個尷尬的解決方案。

反正是有讓我的log4net的屬性設定(無需記住上作出上述呼籲在開始每一個業務操作的 )上正確 線程?

是的。創建一個自定義IOperationInvoker。我所知道的最好的例子是Carlos Figueira's blog如果將此作爲服務行爲應用,則應始終爲服務代碼定義log4net屬性。

一個警告:當添加到線程本地存儲時,一定要清理。這就是爲什麼log4net.ThreadContext.Stacks []。Push()返回一個IDisposable。換句話說,你的Invoke方法應該看起來像(不完整的,未經測試):

public object Invoke(object instance, object[] inputs, out object[] outputs) 
{ 
    using (log4net.ThreadContext.Stacks[key].Push(value)) 
    { 
     return this.originalInvoker.Invoke(instance, inputs, out outputs); 
    } 
} 

見卡洛斯的博客理解爲什麼您呼叫的‘originalInvoker’。請注意,如果您想支持需要實現其他方法的異步操作。

2

是的,IIS可能使用多個線程爲多個WCF請求提供服務。有關更多詳細信息,請參見http://msdn.microsoft.com/en-us/library/cc512374.aspx

您可能會考慮爲每個WCF請求使用不同的記錄器實例。

+0

你說「多線程來服務多個WCF請求」。我正在談論單個WCF調用...(不是多個) – Vaccano 2013-05-01 14:36:30

1

自定義屬性不需要是字符串。所以,你可以在下面的類的實例存儲在全球範圍內:

public class SessionIdProperty 
{ 
    public override string ToString() 
    { 
     // error handling omitted 
     return Session.SessionID; 
    } 
} 

這樣log4net的可以直接訪問Session對象時,它會記錄一條消息。 Log4net在非字符串屬性上調用ToString()方法。

相關問題