現在我們可以確定通過IClientChannelSinkProvider完全可以向Pipeline中插入新的MessageSink。由於SoapClientFormatterSink的存在,我們也完全可以相信這個被插入到ChannelSink鏈中的MessageSink能正常的工作(即執行IMessageSink中的方法,而不是IClIEntChannelSink中的方法),不過為了讓大家更清楚Remoting的底層實現,我們還是想探究一下它是如何調用ChannelSink鏈中的一個個Sink來處理消息的。下圖就是調用一次遠程方法所產生的序列圖:
在上圖中,我們可以看到在InternalInvoke方法中將調用CallProcessMessage方法,它會把消息對象交給ChannelSink鏈中的第一個Sink處理。如下所示:
RemotingProxy.CallProcessMessage(identity.ChannelSink,reqMsg,...);
代碼 5
而我們在上圖中可以發現CallProcessMessage方法的第一個形參是IMessageSink類型的。也就是說通過IClientChannelSinkProvider方式插入到Pipeline中的第一個Sink,反倒是IMessageSink類型的,而不是IClientChannelSink。這也為插入到ChannelSink鏈中的MessageSink能正常工作掃清了障礙。正是因為這個原因SoapClIEntFormatterSink才能發揮其作用。
另外在利用IClIEntChannelSinkProvider插入MessageSink的時候,必須將它插入到FormatterSink的前面。因為只有在消息被Formmat之前,我們才能通過MessageSink對它進行處理,Format之後在Sink對消息的修改就無效了。這點在配置文件中體現為自定義的SinkProvider必須放在Formatter前面。不過這是針對客戶端而言,服務器端則恰恰與此相反。
<channel ref="http">
<clIEntProviders>
<provider type="CustomSinks.CustomSinkProvider,CustomSinks" />
<formatter ref="soap" />
</clIEntProviders>
</channel>
而在客戶端插入ChannelSink時,自定義的SinkProvider都是放在Formatter後面的。你可以在上一篇文章的圖2中發現這點。
總結
在本節中主要介紹了如何利用IClIEntChannelSinkProvider向Pipeline中加入MessageSink,從而在遠程方法調用中修改消息對象,實現功能更強大的擴展。並由此介紹了Remoting在實現此功能時,它的內部實現機制,有助於大家更深入地了解Remoting框架。
下一節將介紹當ClIEnt和Server對象處在同一個Appdomain時,如何攔截並修改消息,其中將涉及到更多類型的Sink。