共用方式為


接收與接收鏈結

本主題專門說明一項為了在現有應用程式中提供回溯相容性而保留的舊有技術,不建議用於新的開發工作。分散式應用程式應使用 Windows Communication Foundation (WCF) 進行開發。

用戶端會將訊息傳送到遠端應用程式定義域中,以針對遠端物件進行方法呼叫。這是透過一組通道物件所完成。用戶端應用程式定義域包含一個用戶端通道,而遠端應用程式定義域則包含一個遠端通道。每個通道都是由一系列連結為同一個鏈結的通道接收所組成。下列圖例顯示基本通道接收鏈結的結構。

接收與接收鏈結

通道會在送出訊息之前或接收訊息之後沿著通道接收物件的鏈結傳送各個訊息。這個接收鏈結包含基本通道功能所必要的接收,例如格式器、傳輸或堆疊產生器接收,但您可以自訂通道接收鏈結來執行處理訊息或資料流的特殊工作。每個通道接收都會實作 IClientChannelSinkIServerChannelSinkfrlrfSystemRuntimeRemotingChannelsIServerChannelSinkClassTopic。用戶端上的第一個通道接收必須同時實作 IMessageSinkfrlrfSystemRuntimeRemotingMessagingIMessageSinkClassTopic,而且通常也會實作 IClientFormatterSink (同時繼承自 IMessageSinkIChannelSinkBaseIClientChannelSink) 並稱為格式器接收,因為它會將傳入的訊息轉換為資料流 (IMessagefrlrfSystemRuntimeRemotingMessagingIMessageClassTopic 物件)。

通道接收鏈結會負責處理任何傳送至應用程式定義域或從其中傳送的訊息。通道接收可存取正在處理的訊息,而後續的處理過程則會使用處理後傳回到系統的訊息。這裡自然是實作記錄服務或任何種類的篩選作業的地方。

每個通道接收會處理資料流,然後將資料流傳遞至下一個通道接收,意即特定接收之前或之後的接收應該知道要如何處理傳遞給它們的資料流。

tdzwhfy3.note(zh-tw,VS.100).gif注意:
訊息接收不可以擲回例外狀況。有一種方式可讓訊息接收控制這種情況的發生,那就是將方法程式碼包裝在 try-catch 區塊中。

通道接收提供者 (實作 IClientChannelSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientChannelSinkProviderClassTopicIClientFormatterSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientFormatterSinkProviderClassTopicIServerChannelSinkProvider 介面的物件) 會負責建立用來處理 .NET 遠端處理訊息的通道接收。一旦啟動遠端型別之後,就會從通道擷取通道接收提供者,並針對接收提供者呼叫 CreateSink 方法,以擷取鏈結中的第一個通道接收。

通道接收負責在用戶端和伺服器之間傳輸訊息,而且也會透過鏈結連結在一起。當針對接收提供者呼叫 CreateSink 方法時,這個方法會執行下列動作:

  • 建立通道接收。

  • 針對鏈結中的下一個接收提供者呼叫 CreateSink

  • 確定下一個接收與目前接收已連結在一起。

  • 將其接收傳回至呼叫者。

通道接收會負責將所有針對本身的呼叫轉送到鏈結的下一個接收,而且應該提供一個將參考儲存到下一個接收的機制。

通道接收在通過接收鏈結往下傳送的項目方面擁有很大的彈性。例如,在傳送實際序列化的原始訊息之前,負責交涉驗證的安全性接收可保留完整的通道訊息,將內容資料流取代為自己的內容,然後將這些訊息通過接收鏈結向下傳送到遠端應用程式定義域中。安全性接收在回程可以攔截回覆訊息,並在遠端應用程式定義域中建立與對應之安全性接收的對話。一旦達成協議,原始的安全性接收就可以將原始內容資料流傳送到遠端應用程式定義域。

通道接收鏈結中的訊息處理

一旦 .NET 遠端處理系統找到可以處理訊息的通道,該通道就會將訊息傳遞到格式器通道接收,方法則是呼叫

SyncProcessMessage (或 AsyncProcessMessage)。格式器接收會建立傳輸標頭陣列,並針對下一個接收呼叫 GetRequestStream。這個呼叫會在接收鏈結中向下轉送,且任何接收都可建立將會傳回格式器接收的要求資料流。如果 GetRequestStream 傳回 null 參考 (在 Visual Basic 中為 Nothing),則格式器接收會建立自己的接收以用於序列化。一旦這個呼叫傳回之後,訊息就會序列化,而且會針對接收鏈結的第一個通道接收呼叫適當的訊息處理方法。

接收無法將資料寫入資料流,但是可以從資料流讀取或視需要傳遞新資料流。接收也可以將標頭加入至標頭陣列 (如果這些標頭先前尚未針對下一個接收呼叫 GetRequestStream),然後將其加入至接收堆疊中,再將呼叫轉送至下一個接收 (完成非同步呼叫之後,同步堆疊會用來允許這些呼叫回呼到呼叫者)。當呼叫到達鏈結結尾的傳輸接收時,傳輸接收會在通道上將標頭和序列化訊息傳送到伺服器,其中整個程序會被反轉。伺服器上的傳輸接收會從資料流的伺服器端擷取標頭和序列化訊息,並透過接收鏈結轉送這些項目,直到抵達格式器接收為止。格式器接收會將訊息還原序列化,並將它轉送至 .NET 遠端處理系統,其中訊息會轉換回方法呼叫並針對伺服器物件叫用。

建立通道接收鏈結

若要建立新的通道接收,您必須實作並將 .NET 遠端處理設為辨識 IServerChannelSinkProviderIClientChannelSinkProvider 實作,如此即可建立您的自訂 IClientChannelSinkIServerChannelSink 實作,或是擷取鏈結中的下一個接收。您可以使用 BaseChannelSinkWithProperties 抽象類別來協助實作您的自訂通道接收。

建置通道接收提供者

在建構通道時,應用程式可提供伺服器或用戶端通道接收提供者做為參數。通道接收提供者應該儲存在鏈結中,而且開發人員也有責任將所有的通道接收提供者鏈結在一起,然後再將外部的通道接收提供者傳遞至通道建構函式。因此,通道接收提供者會實作 Next 屬性。下列程式碼範例將示範如何建置用戶端通道接收提供者。遠端處理範例:通道接收提供者將提供完整的範例。

private Function CreateDefaultClientProviderChain() As IClientChannelSinkProvider
   Dim chain As New FirstClientFormatterSinkProvider            
   Dim sink As IClientChannelSinkProvider
   sink = chain
   sink.Next = New SecondClientFormatterSinkProvider
   sink = sink.Next
   return chain
End Function 
private IClientChannelSinkProvider CreateDefaultClientProviderChain(){
   IClientChannelSinkProvider chain = new FirstClientFormatterSinkProvider();            
   IClientChannelSinkProvider sink = chain;
   sink.Next = new SecondClientFormatterSinkProvider();
   sink = sink.Next;
   return chain;
} 
tdzwhfy3.note(zh-tw,VS.100).gif注意:
當多重通道接收提供者在組態檔中提供時,.NET 遠端處理系統會將它們依照其在組態檔中找到的順序加以鏈結。當通道在 Configure 呼叫期間建立時,會建立通道接收提供者。

格式器接收

格式器接收會將通道訊息序列化到訊息資料流,當做實作 IMessage 的物件使用。某些格式器接收實作會使用系統提供的格式器型別 (BinaryFormatterfrlrfSystemRuntimeSerializationFormattersBinaryBinaryFormatterClassTopicSoapFormatterfrlrfSystemRuntimeSerializationFormattersSoapSoapFormatterClassTopic)。其他實作可以使用它們自己的方法將通道訊息轉換為資料流。

格式器接收的功能是產生所需的標頭,並序列化訊息到資料流。在格式器接收之後,訊息會透過 SyncProcessMessageAsyncProcessMessage 呼叫轉送到接收鏈結的所有接收。訊息在這個階段已序列化,而且無法修改。

tdzwhfy3.note(zh-tw,VS.100).gif注意:
必須建立或修改訊息本身的接收必須比格式器先置入接收鏈結中。實作 IClientFormatterSink 並藉此告訴系統其擁有格式器接收的參考,便可輕鬆達成這個目標。實際的格式器接收稍後可以接著放置到接收鏈結中。

格式器接收會在回程將訊息資料流反向轉換為通道訊息物件 (傳回訊息)。用戶端上的第一個接收必須實作 IClientFormatterSink 介面。當 CreateSink 返回通道,傳回的參考就會轉換為 IClientFormatterSink 型別,以便能夠呼叫 SyncProcessMessage 方法。請記住,IClientFormatterSink 係衍生自 IMessageSink。如果轉換失敗,系統就會引發例外狀況。

自訂通道接收

用戶端上的自訂通道接收會插入到格式器接收與最後一個傳輸接收之間的物件鏈結中。將自動通道接收插入用戶端或伺服器通道中,可讓您在下列其中一個時間點處理 IMessage

  • 在代表訊息的呼叫轉換為資料流,並透過網路傳送的過程中。

  • 在將資料流從網路取下並傳送至伺服器遠端物件或 Proxy 物件 (在用戶端上) 前之最後一個訊息接收的過程中。

自訂接收可以讀取資料或將其寫入資料流中 (需視呼叫為傳出或傳入而定),而且可視需要將額外資訊加入到標頭中。訊息在這個階段已由格式器序列化,而且無法修改。當訊息呼叫轉送到鏈結結尾的傳輸接收時,傳輸接收會將標頭寫入資料流,並使用通道所指定的傳輸通訊協定將資料流轉送到伺服器上的傳輸接收中。

傳輸接收

傳輸接收是用戶端上鏈結的最後一個接收,也是伺服器上鏈結的第一個接收。在傳輸序列化訊息之外,傳輸接收同時需負責將標頭傳送到伺服器,並在呼叫從伺服器傳回時擷取標頭與資料流。這些接收會建置為通道,而且無法延伸。

取代預設的格式器

由於通道是一個抽象的網路機制,因此您可以將 .NET 遠端處理系統設為結合系統實作的通道和您選擇的任何格式器。您可以使用採取通道屬性之 IDictionary 實作、伺服器格式器及用戶端格式器的通道建構函式來達到這個目的,也可以指定組態檔中的格式器。下列範例將指示 .NET 遠端處理組態系統建立 HttpChannel,但是使用用戶端上的 BinaryClientFormatterSink

<configuration>
   <system.runtime.remoting>
      <application>
         <channels>
            <channel ref="http">
               <clientProviders>
                  <formatter ref="binary"/>
               </clientProviders>
         <channels>
      </application>
   </system.runtime.remoting>
</configuration> 

下列程式碼會以程式設計的方式執行相同工作 (假設使用實作 GetServerStringGetServerTime 的遠端介面型別 IService ):

Imports System
Imports System.Collections
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http

Public Class ClientProcess
  <MTAThread()> _
  Public Shared Sub Main()
      
    ' Note that any name/value pairs of configuration attributes can be 
    ' placed in this dictionary (the configuration system calls this same 
    ' constructor).
    Dim properties As New Hashtable()
    properties("name") = "HttpBinary"
     
    ChannelServices.RegisterChannel(New HttpChannel(properties, New BinaryClientFormatterSinkProvider(), Nothing))
    ' The last parameter above (Nothing) is the server sink provider chain 
    ' to obtain the default behavior (which includes SOAP and 
    ' binary formatters on the server side).
    Dim service As IService = CType(Activator.GetObject(GetType(IService), "http://computer:8080/SAService"), IService)
      
    Console.WriteLine("Server string is: " + service.GetServerString())
    Console.WriteLine("Server time is: " + service.GetServerTime())
  End Sub
   
End Class 
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

public class ClientProcess{

  public static void Main(string[] Args){
        
    // Note that any name/value pairs of configuration attributes can be 
    // placed in this dictionary (the configuration system calls this 
    // same HttpChannel constructor).
    IDictionary properties = new Hashtable();
    properties["name"] = "HttpBinary";

    // The last parameter below is the server sink provider chain 
    // to obtain the default behavior (which includes SOAP and binary 
    // formatters) on the server side.
    ChannelServices.RegisterChannel(new HttpChannel(properties, new BinaryClientFormatterSinkProvider(), null));

    IService service = (IService)Activator.GetObject(typeof(IService),"http://computer:8080/SAService");
        
    Console.WriteLine("Server string is: " + service.GetServerString());
    Console.WriteLine("Server time is: " + service.GetServerTime());      
  }
}

如需裝載在網際網路資訊服務 (IIS) 中有關此通道與格式器結合的完整範例,請參閱遠端處理範例:在網際網路資訊服務 (IIS) 中裝載

若要將此用戶端變更為使用 TcpChannel 物件與 SoapClientFormatterSinkfrlrfSystemRuntimeRemotingChannelsSoapClientFormatterSinkClassTopic 物件,您只能變更命名空間與 RegisterChannel **** 呼叫,如下列程式碼所示:

ChannelServices.RegisterChannel(New TcpChannel(properties, New SoapClientFormatterSinkProvider(), Nothing))
ChannelServices.RegisterChannel(new TcpChannel(properties, new SoapClientFormatterSinkProvider(), null));

另請參閱

概念

在網際網路資訊服務 (IIS) 中裝載遠端物件
遠端處理範例:在網際網路資訊服務 (IIS) 中裝載

其他資源

進階遠端處理