好吧,我在回答我自己。
短一:有沒有解決方案。
稍微詳細:
的問題是,我需要一種方法來最後主動操作每個存儲每個邏輯背景。跟蹤代碼將無法控制執行流程,因此不可能將lastStartedOperation作爲參數傳遞。調用上下文可能會克隆(例如,如果另一個線程啓動了),所以我需要克隆作爲上下文克隆的值。 CallContext.LogicalSetData()很適合,但它在異步操作結束時將值合併到原始上下文中(實際上,替換在調用EndInvoke之前所做的所有更改)。理論上,它可能會異步地發生,從而導致CallContext.LogicalGetData()的結果不可預知。
我說理論上是因爲asyncCallback中的簡單調用a.EndInvoke()不會替換原始上下文中的值。雖然,我沒有檢查遠程調用的行爲(看來,WCF根本不尊重CallContext)。此外,documentation(舊)說:
BeginInvoke方法傳遞 CallContext中的服務器。當調用 EndInvoke方法時, CallContext被合併回 線程。這包括其中 BeginInvoke和EndInvoke依次調用 和的情況,其中BeginInvoke是 在一個線程上調用,EndInvoke是 在回調函數上調用。
最後版本沒有那麼明確的:
BeginInvoke方法傳遞 CallContext中的服務器。當調用 EndInvoke方法時,CallContext中包含的數據 被複製 回到調用 BeginInvoke的線程上。
如果你到Digg的框架源代碼,你會發現,值實際存儲在當前線程的當前執行上下文內內LogicalCallContext一個哈希表內。
當調用上下文克隆(例如在BeginInvoke)上調用LogicalCallContext.Clone時。 EndInvoke(至少在原始CallContext中調用時)會調用LogicalCallContext.Merge()替換m_Datastore中的舊值。
所以我們需要以某種方式提供將被克隆但未合併的值。
LogicalCallContext.Clone()還克隆(不合並)兩個專用字段m_RemotingData和m_SecurityData的內容。由於該字段的類型定義爲internal,因此無法從它們派生出來(即使使用emit),請添加屬性MyNoFlowbackValue,並將m_RemotingData(或另一個)字段的值替換爲派生類的實例。
此外,字段的類型不是從MBR派生的,因此不可能使用透明代理來包裝它們。
你不能從LogicalCallContext繼承 - 它是密封的。 (注意事實上,你可以 - 如果使用CLR分析API來替代IL,如同模擬框架一樣,不是理想的解決方案。)
你不能替換m_Datastore值,因爲LogicalCallContext僅序列化哈希表的內容,而不是哈希表本身。
最後的解決方案是使用CallContext.HostContext。這有效地將數據存儲在LogicalCallContext的m_hostContext字段中。 LogicalCallContext.Clone()共享(不克隆)m_hostContext的值,因此該值應該是不可變的。雖然不是問題。
即使使用HttpContext也會失敗,因爲它將CallContext.HostContext屬性設置爲替換舊值。具有諷刺意味的是,HttpContext沒有實現ILogicalThreadAffinative,因此不存儲爲m_hostContext字段的值。它只是用null替換舊值。
因此,沒有解決方案,永遠不會,因爲CallContext是遠程處理的一部分,遠程處理已經過時。
P.S. Thace.CorrelationManager在內部使用CallContext,因此也不能按需要工作。順便說一下,LogicalCallContext有一個特殊的解決方法來克隆上下文克隆上的CorrelationManager的操作棧。可悲的是,它沒有專門的合併解決方法。完善!
P.P.S.示例:
static void Main(string[] args)
{
string key = "aaa";
EventWaitHandle asyncStarted = new AutoResetEvent(false);
IAsyncResult r = null;
CallContext.LogicalSetData(key, "Root - op 0");
Console.WriteLine("Initial: {0}", CallContext.LogicalGetData(key));
Action a =() =>
{
CallContext.LogicalSetData(key, "Async - op 0");
asyncStarted.Set();
};
r = a.BeginInvoke(null, null);
asyncStarted.WaitOne();
Console.WriteLine("AsyncOp started: {0}", CallContext.LogicalGetData(key));
CallContext.LogicalSetData(key, "Root - op 1");
Console.WriteLine("Current changed: {0}", CallContext.LogicalGetData(key));
a.EndInvoke(r);
Console.WriteLine("Async ended: {0}", CallContext.LogicalGetData(key));
Console.ReadKey();
}
感謝您提供非常詳細的資料,對我來說非常有用的信息,而且我認識到它很難找到!感謝您發佈它 – 2012-08-10 17:27:38