天天看點

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

在上一篇文章中,我們讨論了如何通過CallContextInitializer實作Localization的例子,具體的做法是将client端的culture通過SOAP header傳到service端,然後通過自定義的CallContextInitializer設定目前方法執行的線程culture。在client端,目前culture資訊是通過OperationContext.Current.OutgoingMessageHeaders手工至于SOAP Header中的。實際上,我們可以通過基于WCF的另一個可擴充對象來實作這段邏輯,這個可擴充對象就是MessageInspector。我們今天來讨論MessageInspector應用的另外一個場景:如何通過MessageInspector來傳遞Context資訊。

1. Ambient Context

在一個多層結構的應用中,我們需要傳遞一些上下文的資訊在各層之間傳遞,比如:為了進行Audit,需要傳遞一些目前目前user profile的一些資訊。在一些分布式的環境中也可能遇到context資訊從client到server的傳遞。如何實作這種形式的Context資訊的傳遞呢?我們有兩種方案:

一、将Context作為參數傳遞:将context作為API的一部分,context的提供者在調用context接收者的API的時候顯式地設定這些Context資訊,context的接收者則直接通過參數将context取出。這雖然能夠解決問題,但決不是一個好的解決方案,因為API應該隻和具體的業務邏輯有關,而context 一般是與非業務邏輯服務的,比如Audit、Logging等等。此外,将context納入API作為其一部分,将降低API的穩定性, 比如,今天隻需要目前user所在組織的資訊,明天可能需求擷取目前用戶端的IP位址,你的API可以會經常變動,這顯然是不允許的。

二、建立Ambient Context來儲存這些context資訊,Ambient Context可以在不同的層次之間、甚至是分布式環境中每個節點之間共享或者傳遞。比如在ASP.NET 應用中,我們通過SessionSate來存儲目前Session的資訊;通過HttpContext來存儲目前Http request的資訊。在非Web應用中,我們通過CallContext将context資訊存儲在TLS(Thread Local Storage)中,目前線程下執行的所有代碼都可以通路并設定這些context資料。

2、Application Context

介于上面所述,我建立一個名為Application Context的Ambient Context容器,Application Context實際上是一個dictionary對象,通過key-value pair進行context元素的設定,通過key擷取相對應的context元素。Application Context通過CallContext實作,定義很簡單:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    [Serializable]

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public class ApplicationContext:Dictionary<string,object>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        private const string CallContextKey = "__ApplicationContext";    

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        internal const string ContextHeaderLocalName = "__ApplicationContext";

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        internal const string ContextHeaderNamespace = "urn:artech.com"; 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        private void EnsureSerializable(object value)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (value == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                throw new ArgumentNullException("value");

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (!value.GetType().IsSerializable)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                throw new ArgumentException(string.Format("The argument of the type /"

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{0}/" is not serializable!", value.GetType().FullName));

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        }       

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public new  object this[string key]

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            get

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return base[key];

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            set

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                this.EnsureSerializable(value);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                base[key] = value;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public int Counter

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            get

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

               return (int)this["__Count"];

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            set

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                this["__Count"] = value;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public static ApplicationContext Current

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            get

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                if (CallContext.GetData(CallContextKey) == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                    CallContext.SetData(CallContextKey, new ApplicationContext());

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return CallContext.GetData(CallContextKey) as ApplicationContext;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            set

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                CallContext.SetData(CallContextKey, value);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        }     

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

由于此Context将會置于SOAP Header中從client端向service端進行傳遞,我們需要為此message header指定一個local name和namespace,那麼在service端,才能通過此local name和namespace獲得此message header。同時,在lcoal domain, client或者service,context是通過CallContext進行存取的,CallContext也是一個類似于disctionary的結構,也需要為此定義一個Key:

private const string CallContextKey = "__ApplicationContext"; internal const string ContextHeaderLocalName = "__ApplicationContext";

internal const string ContextHeaderNamespace = "urn:artech.com";

由于ApplicaitonContext直接繼承自Dictionary<string,object>,我們可以通過Index進行元素的設定和提取,考慮到context的跨域傳播,需要進行序列化,是以重寫了Indexer,并添加了可序列化的驗證。為了後面示範方面,我們定義一個context item:Counter。

Static類型的Current屬性通過CallContext的SetData和GetData方法對目前的ApplicationContext進行設定和提取:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

public static ApplicationContext Current

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            get

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                if (CallContext.GetData(CallContextKey) == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                    CallContext.SetData(CallContextKey, new ApplicationContext());

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return CallContext.GetData(CallContextKey) as ApplicationContext;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            set

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                CallContext.SetData(CallContextKey, value);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

}     

3、通過MessageInspector将AppContext置于SOAP header中

通過本系列第3部分對Dispatching system的介紹了,我們知道了在client端和service端,可以通過MessageInspector對request message或者reply message (incoming message或者outgoings message)進行檢驗。MessageInspector可以對MessageHeader進行自由的添加、修改和删除。在service端的MessageInspector被稱為DispatchMessageInspector,相對地,client端被稱為ClientMessageInspector。我們現在自定義我們自己的ClientMessageInspector。

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public class ContextAttachingMessageInspector:IClientMessageInspector

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public bool IsBidirectional

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{ get; set; } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public ContextAttachingMessageInspector()

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            : this(false)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{ } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public ContextAttachingMessageInspector(bool isBidirectional)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            this.IsBidirectional = IsBidirectional;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        IClientMessageInspector Members#region IClientMessageInspector Members 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void AfterReceiveReply(ref Message reply, object correlationState)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (IsBidirectional)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (reply.Headers.FindHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace) < 0)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext context = reply.Headers.GetHeader<ApplicationContext>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (context == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext.Current = context;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public object BeforeSendRequest(ref Message request, IClientChannel channel)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            MessageHeader<ApplicationContext> contextHeader = new MessageHeader<ApplicationContext>(ApplicationContext.Current);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            request.Headers.Add(contextHeader.GetUntypedHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace));

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            return null;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        #endregion

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

一般地,我們僅僅需要Context的單向傳遞,也就是從client端向service端傳遞,而不需要從service端向client端傳遞。不過回來應付将來潛在的需求,也許可能需要這樣的功能:context從client端傳向service端,service對其進行修改後需要将其傳回到client端。為此,我們家了一個屬性:IsBidirectional表明是否支援雙向傳遞。

在BeforeSendRequest,我們将ApplicationContext.Current封裝成一個MessageHeader, 并将此MessageHeader添加到request message 的header集合中,local name和namespace采用的是定義在ApplicationContext中常量:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

public object BeforeSendRequest(ref Message request, IClientChannel channel)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            MessageHeader<ApplicationContext> contextHeader = new MessageHeader<ApplicationContext>(ApplicationContext.Current);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            request.Headers.Add(contextHeader.GetUntypedHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace));

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            return null;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

如何支援context的雙向傳遞,我們在AfterReceiveReply負責從reply message中接收從service傳回的context,并将其設定成目前的context:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

public   void  AfterReceiveReply( ref  Message reply,  object  correlationState)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        if (IsBidirectional)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        if (reply.Headers.FindHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace) < 0)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

             return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        ApplicationContext context = reply.Headers.GetHeader<ApplicationContext>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        if (context == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        ApplicationContext.Current = context;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

}  

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

4、通過ContextInitializer實作對Context的接收

上面我們介紹了在client端通過ClientMessageInspector将context資訊存儲到request message header中,照理說我們通過可以通過DispatchMessageInspector實作對context資訊的提取,但是考慮到我們設定context是通過CallContext來實作了,我們最好還是使用CallContextInitializer來做比較好一些。CallContextInitializer的定義,我們在上面一章已經作了詳細的介紹了,在這裡就不用多說什麼了。

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public class ContextReceivalCallContextInitializer : ICallContextInitializer

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public bool IsBidirectional

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{ get; set; } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public ContextReceivalCallContextInitializer()

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            : this(false)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{ } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public ContextReceivalCallContextInitializer(bool isBidirectional)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            this.IsBidirectional = isBidirectional;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        ICallContextInitializer Members#region ICallContextInitializer Members 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void AfterInvoke(object correlationState)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (!this.IsBidirectional)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext context = correlationState as ApplicationContext;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (context == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            MessageHeader<ApplicationContext> contextHeader = new MessageHeader<ApplicationContext>(context);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            OperationContext.Current.OutgoingMessageHeaders.Add(contextHeader.GetUntypedHeader(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace));

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext.Current = null;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext context = message.Headers.GetHeader<ApplicationContext>(ApplicationContext.ContextHeaderLocalName, ApplicationContext.ContextHeaderNamespace);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            if (context == null)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return null;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext.Current = context;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            return ApplicationContext.Current;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        #endregion

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

代碼其實很簡單,BeforeInvoke中通過local name和namespace提取context對應的message header,并設定目前的ApplicationContext。如果需要雙向傳遞,則通過AfterInvoke方法将context儲存到reply message的header中被送回client端。

5. 為MessageInspector和CallContextInitializer建立behavior:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public class ContextPropagationBehavior: IEndpointBehavior

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public bool IsBidirectional

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{ get; set; } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public ContextPropagationBehavior()

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            : this(false)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{ } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public ContextPropagationBehavior(bool isBidirectional)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            this.IsBidirectional = isBidirectional;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        IEndpointBehavior Members#region IEndpointBehavior Members 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            clientRuntime.MessageInspectors.Add(new ContextAttachingMessageInspector(this.IsBidirectional));

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            foreach (var operation in endpointDispatcher.DispatchRuntime.Operations)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                operation.CallContextInitializers.Add(new ContextReceivalCallContextInitializer(this.IsBidirectional));

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void Validate(ServiceEndpoint endpoint)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        #endregion

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

在ApplyClientBehavior中,建立我們的ContextAttachingMessageInspector對象,并将其放置到ClientRuntime 的MessageInspectors集合中;在ApplyDispatchBehavior,将ContextReceivalCallContextInitializer對象放到每個DispatchOperation的CallContextInitializers集合中。

因為我們需要通過配置的方式來使用我們的ContextPropagationBehavior,我們還需要定義對應的BehaviorExtensionElement:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public class ContextPropagationBehaviorElement:BehaviorExtensionElement

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        [ConfigurationProperty("isBidirectional", DefaultValue = false)]

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public bool IsBidirectional

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            get

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return (bool)this["isBidirectional"];

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            set

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                this["isBidirectional"] = value;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public override Type BehaviorType

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            get 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                return typeof(ContextPropagationBehavior); 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        protected override object CreateBehavior()

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            return new ContextPropagationBehavior(this.IsBidirectional);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

我們IsBidirectional則可以通過配置的方式來指定。

6. Context Propagation的運用

我們現在将上面建立的對象應用到真正的WCF調用環境中。我們依然建立我們經典的4層結構:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
  • Artech.ContextPropagation.Contract:
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace  Artech.ContextPropagation.Contract

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    [ServiceContract]

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public interface IContract

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        [OperationContract]

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        void DoSomething();

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

}  

  • Artech.ContextPropagation.Services
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation.Services

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    public class Service:IContract

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        IContract Members#region IContract Members

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        public void DoSomething()

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            Console.WriteLine("ApplicationContext.Current.Count = {0}", ApplicationContext.Current.Counter);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            ApplicationContext.Current.Counter++;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        } 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        #endregion

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

列印出ApplicationContext.Current.Count 的值,并加1。

  • Hosting的Config:
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

<configuration>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    <system.serviceModel>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        <behaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            <endpointBehaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                <behavior name="contextPropagationBehavior">

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                    <contextPropagationElement isBidirectional="true" />

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                </behavior>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            </endpointBehaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        </behaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        <client>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            <endpoint address="http://127.0.0.1/service" behaviorConfiguration="contextPropagationBehavior"

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                binding="basicHttpBinding" contract="Artech.ContextPropagation.Contract.IContract"

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                name="service" />

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        </client>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        <extensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            <behaviorExtensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                <add name="contextPropagationElement" type="Artech.ContextPropagation.ContextPropagationBehaviorElement, Artech.ContextPropagation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            </behaviorExtensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        </extensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    </system.serviceModel>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

</configuration>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

Artech.ContextPropagation.Client

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

namespace Artech.ContextPropagation.Client

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    class Program

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        static void Main(string[] args)

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            using (ChannelFactory<IContract> channelFactory = new ChannelFactory<IContract>("service"))

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

{

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                IContract proxy = channelFactory.CreateChannel();

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                ApplicationContext.Current.Counter = 100;

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                Console.WriteLine("Brfore service invocation: ApplicationContext.Current.Count = {0}", ApplicationContext.Current.Counter);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                proxy.DoSomething();

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                Console.WriteLine("After service invocation: ApplicationContext.Current.Count = {0}", ApplicationContext.Current.Counter);

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                Console.Read();

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    }

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

以及config:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

<configuration>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    <system.serviceModel>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        <behaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            <endpointBehaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

               <behavior name="contextPropagationBehavior">

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                    <contextPropagationElement isBidirectional="true" />

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                </behavior>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            </endpointBehaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        </behaviors>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        <client>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            <endpoint address="http://127.0.0.1/service" behaviorConfiguration="contextPropagationBehavior"

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                binding="basicHttpBinding" contract="Artech.ContextPropagation.Contract.IContract"

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                name="service" />

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        </client>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        <extensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            <behaviorExtensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

                <add name="contextPropagationElement" type="Artech.ContextPropagation.ContextPropagationBehaviorElement, Artech.ContextPropagation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

            </behaviorExtensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

        </extensions>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

    </system.serviceModel>

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

</configuration> 

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞
[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

我們運作整個程式,你将會看到如下的輸出結果:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

可見,Context被成功傳播到service端。再看看client端的輸出:

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

由此可見,在service端設定的context的值也成功傳回到client端,真正實作了雙向傳遞。

P.S: SOA主張Stateless的service,也就是說每次調用service都應該是互相獨立的。context的傳遞實際上卻是讓每次通路有了狀态,這實際上是違背了SOA的原則。是以,如何對于真正的SOA的設計與架構,個人覺得這種方式是不值得推薦的。但是,如何你僅僅是将WCF作為傳統的分布式手段,那麼這可能會給你的應用帶了很大的便利。

WCF後續之旅:

[原創]WCF後續之旅(1): WCF是如何通過Binding進行通信的

[原創]WCF後續之旅(2): 如何對Channel Layer進行擴充——建立自定義Channel

[原創]WCF後續之旅(3): WCF Service Mode Layer 的中樞—Dispatcher

[原創]WCF後續之旅(4):WCF Extension Point 概覽

[原創]WCF後續之旅(5): 通過WCF Extension實作Localization

[原創]WCF後續之旅(6): 通過WCF Extension實作Context資訊的傳遞

[原創]WCF後續之旅(7):通過WCF Extension實作和Enterprise Library Unity Container的內建

[原創]WCF後續之旅(8):通過WCF Extension 實作與MS Enterprise Library Policy Injection Application Block 的內建

[原創]WCF後續之旅(9):通過WCF的雙向通信實作Session管理[Part I]

[原創]WCF後續之旅(9): 通過WCF雙向通信實作Session管理[Part II]

[原創]WCF後續之旅(10): 通過WCF Extension實作以對象池的方式建立Service Instance

我的WCF之旅:

[原創]我的WCF之旅(1):建立一個簡單的WCF程式

[原創]我的WCF之旅(2):Endpoint Overview

[原創]我的WCF之旅(3):在WCF中實作雙向通信(Bi-directional Communication)

[原創]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I

[原創]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II

[原創]我的WCF之旅(5):Service Contract中的重載(Overloading)

[原創]我的WCF之旅(6):在Winform Application中調用Duplex Service出現TimeoutException的原因和解決方案

[原創]我的WCF之旅(7):面向服務架構(SOA)和面向對象程式設計(OOP)的結合——如何實作Service Contract的繼承

[原創]我的WCF之旅(8):WCF中的Session和Instancing Management

[原創]我的WCF之旅(9):如何在WCF中使用tcpTrace來進行Soap Trace

[原創]我的WCF之旅(10): 如何在WCF進行Exception Handling

[原創]我的WCF之旅(11):再談WCF的雙向通訊-基于Http的雙向通訊 V.S. 基于TCP的雙向通訊

[原創]我的WCF之旅(12):使用MSMQ進行Reliable Messaging

[原創]我的WCF之旅(13):建立基于MSMQ的Responsive Service

繼續閱讀