不知你是否記得之前提到的四個接口:IContributeEnvoySink、IContributeServerContextSink、IContributeObjectSink、IContributeClIEntContextSink。其實它們分別代表了四個不同的消息接收器區域:服務器(server)區域、對象(object)區域、信使(envoy)區域和客戶端(clIEnt)區域。要理解區域概念,你必須考慮上下文綁定的對象是否被位於另一個上下文的實體調用。這個實體可以是一個靜態方法或者另一個對象。在我們關於區域的討論中,我們把這個實體所在的上下文稱為調用方上下文(calling context),而把被調用對象所在的上下文稱為目標上下文(target context)。目標上下文中的每個屬性都可以在這些區域中注入消息接收器。
·注入服務器區域的消息接收器攔截所有從另一個上下文發往目標上下文中所有對象的調用消息。於是,每個目標上下文有一個服務器區域。
·注入對象區域的消息接收器攔截所有從另一個上下文發往目標對象中特定對象的調用消息。於是,上下文中每個對象會有一個對象區域。
·注入信使區域的消息接收器攔截所有從另一個上下文發往目標對象中特定對象的調用消息。信使區域和對象區域的不同點是信使區域位於調用方上下文而不是包含對象的目標上下文。我們使用信使區域把調用方上下文的信息傳遞給目標上下文的消息接收器。
·注入客戶端區域的消息接收器攔截所有從目標上下文發往位於其他上下文的對象的調用消息。於是,每個目標上下文有一個客戶端區域。你可能會對這個區域所處的位置有點困惑,似乎當它位於Calling context的信使區域下方時會顯得更加對稱。之所以會有這樣的誤解,是因為我們對Server、Client的理解有了偏差。你應該記住除了信使區域是位於Calling context外,另外三個區域都是處在Target Context。而所謂的Server,ClIEnt是針對處在Target Context中的對象在某不同時刻所扮演不同角色而言的。當然Calling context中也會有客戶端區域,不過其中的MessageSink不是通過Target context的屬性注入的,而應該依靠Calling context中的上下文屬性注入。
上圖說明了區域的概念。目標上下文包含名為OBJ1和OBJ2的兩個對象。我們選擇在目標上下文中放置兩個對象而不是一個是為了更好地說明對象區域和信使區域是在對象層面與消息的攔截關聯起來的,而服務器區域和客戶端區域則是在上下文層面與消息的攔截關聯起來的。
我們在每個區域中放置了兩個自定義消息接收器是為了更好地說明一個區域能包含零個、一個或多個消息接收器。具體地說,所有自定義消息接收器都通過目標上下文的屬性注入區域,即使這個區域不屬於目標上下文。因為你可以定義你自己的上下文屬性類,你可以選擇必須注入哪個消息接收器。
你可能注意到每個區域都包含一個用於通知CLR退出區域的系統終結器接收器(system terminator sink),它是由Remoting框架定義的,並且總是位於每個區域的末尾。
當調用方上下文和目標上下文處在同一個應用程序域中時,CLR會使用mscorlib.dll中CrossContextChannel內部類的實例作為信道。這個實例會使得當前線程的Context屬性發生切換。圖中也展示了這一實例。