Transport: WSE 3.0-TCP-InteroperabilitätTransport: WSE 3.0 TCP Interoperability

Das Beispiel zum WSE 3.0-TCP-Interoperabilitätstransport veranschaulicht, wie eine TCP-Duplexsitzung als ein benutzerdefinierter Windows Communication Foundation (WCF)Windows Communication Foundation (WCF)-Transport implementiert wird.The WSE 3.0 TCP Interoperability Transport sample demonstrates how to implement a TCP duplex session as a custom Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) transport. Außerdem zeigt es, wie Sie die Erweiterbarkeit der Kanalschicht verwenden können, um über das Netzwerk auf vorhandene bereitgestellte Systeme zuzugreifen.It also demonstrates how you can use the extensibility of the channel layer to interface over the wire with existing deployed systems. Die folgenden Schritte veranschaulichen, wie dieser benutzerdefinierte WCFWCF-Transport erstellt wird:The following steps show how to build this custom WCFWCF transport:

  1. Beginnen Sie mit einem TCP-Socket. Erstellen Sie Client- und Serverimplementierungen von IDuplexSessionChannel, die Nachrichtenbegrenzungen mittels DIME Framing voneinander abgrenzen.Starting with a TCP socket, create client and server implementations of IDuplexSessionChannel that use DIME Framing to delineate message boundaries.

  2. Erstellen Sie eine Kanalfactory, die mit einem WSE-TCP-Dienst verbunden wird und begrenzte Nachrichten über die IDuplexSessionChannels sendet.Create a channel factory that connects to a WSE TCP service and sends framed messages over the client IDuplexSessionChannels.

  3. Erstellen Sie einen Kanallistener zum Entgegennehmen eingehender TCP-Verbindungen, und generieren Sie entsprechende Kanäle.Create a channel listener to accept incoming TCP connections and produce corresponding channels.

  4. Stellen Sie sicher, dass alle netzwerkspezifischen Ausnahmen zu der entsprechenden abgeleiteten Klasse von CommunicationException normalisiert werden.Ensure that any network-specific exceptions are normalized to the appropriate derived class of CommunicationException.

  5. Fügen Sie ein Bindungselement hinzu, das den benutzerdefinierten Transport einem Kanalstapel hinzufügt.Add a binding element that adds the custom transport to a channel stack. Weitere Informationen finden Sie unterFor more information, see[Hinzufügen eines Bindungselements]. [Adding a Binding Element].

Erstellen von IDuplexSessionChannelCreating IDuplexSessionChannel

Der erste Schritt beim Schreiben des WSE 3.0-TCP-Interoperabilitätstransports besteht im Erstellen einer Implementierung von IDuplexSessionChannel auf einem Socket.The first step in writing the WSE 3.0 TCP Interoperability Transport is to create an implementation of IDuplexSessionChannel on top of a Socket. WseTcpDuplexSessionChannel wird von ChannelBase abgeleitet.WseTcpDuplexSessionChannel derives from ChannelBase. Die Logik zum Senden von Nachrichten besteht aus zwei Hauptteilen: (1) dem Codieren der Nachricht in Bytes und (2) dem Einrahmen und Senden dieser Bytes über das Netzwerk.The logic of sending a message consists of two main pieces: (1) Encoding the message into bytes, and (2) framing those bytes and sending them on the wire.

ArraySegment<byte> encodedBytes = EncodeMessage(message);

WriteData(encodedBytes);

Außerdem wird eine Sperre angewendet, sodass die Send()-Aufrufe die IduplexSessionChannel-Reihenfolgen-Garantie beibehalten und Aufrufe an den zugrunde liegenden Socket korrekt synchronisiert werden.In addition, a lock is taken so that the Send() calls preserve the IDuplexSessionChannel in-order guarantee, and so that calls to the underlying socket are synchronized correctly.

WseTcpDuplexSessionChannel verwendet einen MessageEncoder zum Übersetzen eines Message in und aus Byte[].WseTcpDuplexSessionChannel uses a MessageEncoder for translating a Message to and from byte[]. Da es sich um einen Transport handelt, ist WseTcpDuplexSessionChannel auch dafür verantwortlich, dass die Remoteadresse angewendet wird, mit der der Kanal konfiguriert wurde.Because it is a transport, WseTcpDuplexSessionChannel is also responsible for applying the remote address that the channel was configured with. EncodeMessage kapselt die Logik für diese Konvertierung.EncodeMessage encapsulates the logic for this conversion.

this.RemoteAddress.ApplyTo(message);

return encoder.WriteMessage(message, maxBufferSize, bufferManager);

Wenn die Message-Instanz in Bytes codiert ist, muss sie über das Netzwerk gesendet werden.Once the Message is encoded into bytes, it must be transmitted on the wire. Dazu ist ein System zum Definieren von Nachrichtenbegrenzungen erforderlich.This requires a system for defining message boundaries. WSE 3.0 verwendet eine Version der DIME liegendes Framing-Protokoll.WSE 3.0 uses a version of DIME as its framing protocol. WriteData kapselt die Framinglogik zum Einschließen eines Byte[] in einen Satz von DIME-Datensätzen.WriteData encapsulates the framing logic to wrap a byte[] into a set of DIME records.

Die Logik zum Empfangen von Nachrichten ist sehr ähnlich.The logic for receiving messages is very similar. Das Hauptproblem besteht darin, mit dem Umstand umzugehen, dass ein Socketlesevorgang weniger Bytes als angefordert zurückgeben kann.The main complexity is handling the fact that a socket read can return less bytes than were requested. Zum Empfangen einer Nachricht liest WseTcpDuplexSessionChannel Bytes aus dem Netzwerk, decodiert das DIME-Framing und wandelt dann mithilfe von MessageEncoder das Byte[] in eine Message um.To receive a message, WseTcpDuplexSessionChannel reads bytes off the wire, decodes the DIME framing, and then uses the MessageEncoder for turning the byte[] into a Message.

Der Basis-WseTcpDuplexSessionChannel geht davon aus, dass er einen verbundenen Socket empfängt.The base WseTcpDuplexSessionChannel assumes that it receives a connected socket. Die Basisklasse behandelt das Herunterfahren des Sockets.The base class handles socket shutdown. Es gibt drei Stellen, die mit einer Schließung des Sockets in Verbindung stehen:There are three places that interface with socket closure:

  • OnAbort -- schließt den Socket nicht ordnungsgemäß ("hartes" Schließen).OnAbort -- close the socket ungracefully (hard close).

  • On[Begin]Close -- schließt den Socket ordnungsgemäß ("weiches" Schließen).On[Begin]Close -- close the socket gracefully (soft close).

  • session.CloseOutputSession -- fährt den ausgehenden Datenstream herunter ("halbes" Schließen).session.CloseOutputSession -- shutdown the outbound data stream (half close).

KanalfactoryChannel Factory

Der nächste Schritt beim Schreiben des TCP-Transports besteht im Erstellen einer Implementierung von IChannelFactory für Clientkanäle.The next step in writing the TCP transport is to create an implementation of IChannelFactory for client channels.

  • WseTcpChannelFactoryleitet sich von ChannelFactoryBase <IDuplexSessionChannel >.WseTcpChannelFactory derives from ChannelFactoryBase<IDuplexSessionChannel>. Das ist eine Factory, die OnCreateChannel überschreibt, um Clientkanäle zu erzeugen.It is a factory that overrides OnCreateChannel to produce client channels.

protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)

{

return new ClientWseTcpDuplexSessionChannel(encoderFactory, bufferManager, remoteAddress, via, this);

}

  • ClientWseTcpDuplexSessionChannelFügt der Logik zur Basis WseTcpDuplexSessionChannel zur Verbindung mit eines TCP-Servers channel.Open Zeit.ClientWseTcpDuplexSessionChannel adds logic to the base WseTcpDuplexSessionChannel to connect to a TCP server at channel.Open time. Zuerst wird der Hostname zu einer IP-Adresse aufgelöst, wie im folgenden Code dargestellt.First the hostname is resolved to an IP address, as shown in the following code.

hostEntry = Dns.GetHostEntry(Via.Host);

  • Dann wird der Hostname in einer Schleife mit der ersten verfügbaren IP-Adresse verbunden, wie im folgenden Code dargestellt.Then the hostname is connected to the first available IP address in a loop, as shown in the following code.

IPAddress address = hostEntry.AddressList[i];

socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

socket.Connect(new IPEndPoint(address, port));

  • Als Teil des Kanalvertrags werden alle domänenspezifischen Ausnahmen eingebunden (wie SocketException in CommunicationException).As part of the channel contract, any domain-specific exceptions are wrapped, such as SocketException in CommunicationException.

KanallistenerChannel Listener

Im nächsten Schritt wird eine Implementierung von IChannelListener zum Entgegennehmen von Serverkanälen erstellt.The next step in writing the TCP transport is to create an implementation of IChannelListener for accepting server channels.

  • WseTcpChannelListenerleitet sich von ChannelListenerBase <IDuplexSessionChannel > und Außerkraftsetzungen [Begin] Open und On [Begin] nahe an die Lebensdauer seines lauschsockets zu steuern.WseTcpChannelListener derives from ChannelListenerBase<IDuplexSessionChannel> and overrides On[Begin]Open and On[Begin]Close to control the lifetime of its listen socket. In OnOpen wird ein Socket zum Lauschen an IP_ANY erstellt.In OnOpen, a socket is created to listen on IP_ANY. Weiter fortgeschrittene Implementierungen können einen zweiten Socket erstellen, um auch an IPv6 zu lauschen.More advanced implementations can create a second socket to listen on IPv6 as well. Sie können außerdem zulassen, dass die IP-Adresse im Hostnamen angegeben wird.They can also allow the IP address to be specified in the hostname.

IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, uri.Port);

this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

this.listenSocket.Bind(localEndpoint);

this.listenSocket.Listen(10);

Wenn ein neuer Socket entgegengenommen ist, wird ein Serverkanal mit diesem Socket initialisiert.When a new socket is accepted, a server channel is initialized with this socket. Alle Ein- und Ausgaben sind bereits in der Basisklasse implementiert, daher dient dieser Kanal zum Initialisieren des Sockets.All the input and output is already implemented in the base class, so this channel is responsible for initializing the socket.

Hinzufügen eines BindungselementsAdding a Binding Element

Nachdem nun die Factorys und Kanäle erstellt sind, müssen sie der ServiceModel-Laufzeit über eine Bindung verfügbar gemacht werden.Now that the factories and channels are built, they must be exposed to the ServiceModel runtime through a binding. Eine Bindung ist eine Auflistung von Bindungselementen, die den mit einer Dienstadresse verknüpften Kommunikationsstapel darstellt.A binding is a collection of binding elements that represents the communication stack associated with a service address. Jedes Element im Stapel wird durch ein Bindungselement dargestellt.Each element in the stack is represented by a binding element.

Im Beispiel ist das Bindungselement WseTcpTransportBindingElement, das von TransportBindingElement abgeleitet wird.In the sample, the binding element is WseTcpTransportBindingElement, which derives from TransportBindingElement. Es unterstützt IDuplexSessionChannel und überschreibt die folgenden Methoden, um die mit unserer Bindung verknüpften Factorys zu erstellen.It supports IDuplexSessionChannel and overrides the following methods to build the factories associated with our binding.

public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)

{

return (IChannelFactory<TChannel>)(object)new WseTcpChannelFactory(this, context);

}

public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)

{

return (IChannelListener<TChannel>)(object)new WseTcpChannelListener(this, context);

}

Es enthält auch Members zum Klonen des BindingElement und Zurückgeben unseres Schemas (wse.tcp).It also contains members for cloning the BindingElement and returning our scheme (wse.tcp).

Die WSE-TCP-TestkonsoleThe WSE TCP Test Console

Testcode zum Verwenden dieses Beispieltransports ist in TestCode.cs verfügbar.Test code for using this sample transport is available in TestCode.cs. Die folgenden Anweisungen zeigen, wie das WSE-TcpSyncStockService-Beispiel erstellt wird.The following instructions show how to set up the WSE TcpSyncStockService sample.

Der Testcode erstellt eine benutzerdefinierte Bindung, die MTOM als Codierung und WseTcpTransport als Transport verwendet.The test code creates a custom binding that uses MTOM as the encoding and WseTcpTransport as the transport. Außerdem richtet er die AddressingVersion so ein, dass sie mit WSE 3.0 kompatibel ist, wie im folgenden Code dargestellt.It also sets up the AddressingVersion to be conformant with WSE 3.0, as shown in the following code.

CustomBinding binding = new CustomBinding();

MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();

mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;

binding.Elements.Add(mtomBindingElement);

binding.Elements.Add(new WseTcpTransportBindingElement());

Er besteht aus zwei Tests: Der erste Test richtet einen typisierten Client mithilfe von aus WSE 3.0 WSDL generiertem Code ein.It consists of two tests—one test sets up a typed client using code generated from the WSE 3.0 WSDL. Der zweite Test verwendet WCFWCF sowohl als Client als auch als Server, indem er Nachrichten direkt über die Kanal-APIs sendet.The second test uses WCFWCF as both the client and the server by sending messages directly on top of the channel APIs.

Beim Ausführen des Beispiels sollte die Ausgabe wie folgt aussehen.When running the sample, the following output is expected.

Client:Client:

Calling soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService  

Symbol: FABRIKAM  
        Name: Fabrikam, Inc.  
        Last Price: 120  

Symbol: CONTOSO  
        Name: Contoso Corp.  
        Last Price: 50.07  
Press enter.  

Received Action: http://SayHello  
Received Body: to you.  
Hello to you.  
Press enter.  

Received Action: http://NotHello  
Received Body: to me.  
Press enter.  

Server:Server:

Listening for messages at soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService  

Press any key to exit when done...  

Request received.  
Symbols:  
        FABRIKAM  
        CONTOSO  

So können Sie das Beispiel einrichten, erstellen und ausführenTo set up, build, and run the sample

  1. Um dieses Beispiel ausführen zu können, müssen WSE 3.0 und das WSE-TcpSyncStockService-Beispiel installiert sein.To run this sample, you must have WSE 3.0 and the WSE TcpSyncStockService sample installed. Sie können herunterladen WSE 3.0 von MSDN.You can download WSE 3.0 from MSDN.

Hinweis

Da WSE 3.0 von Windows Server 2008Windows Server 2008 nicht unterstützt wird, können Sie das TcpSyncStockService-Beispiel unter diesem Betriebssystem nicht installieren und ausführen.Because WSE 3.0 is not supported on Windows Server 2008Windows Server 2008, you cannot install or run the TcpSyncStockService sample on that operating system.

  1. Führen Sie nach der Installation des TcpSyncStockService-Beispiels folgende Schritte aus:Once you install the TcpSyncStockService sample, do the following:

    1. Öffnen Sie den TcpSyncStockService in Visual Studio. (Das TcpSyncStockService-Beispiel wird mit WSE 3.0 installiert.Open the TcpSyncStockService in Visual Studio (Note that the TcpSyncStockService sample is installed with WSE 3.0. Es ist nicht Bestandteil dieses Beispielcodes.)It is not part of this sample's code).

    2. Legen Sie das StockService-Projekt als Startprojekt fest.Set the StockService project as the start up project.

    3. Öffnen Sie StockService.cs im StockService-Projekt, und kommentieren Sie das [Policy]-Attribut in der StockService-Klasse aus.Open StockService.cs in the StockService project and comment out the [Policy] attribute on the StockService class. Dadurch werden die Sicherheitsfunktionen im Beispiel deaktiviert.This disables security from the sample. Obwohl WCFWCF mit WSE 3.0-Sicherheitsendpunkten interagieren kann, ist die Sicherheit deaktiviert, um dieses Beispiel auf den benutzerdefinierten TCP-Transport zu konzentrieren.While WCFWCF can interoperate with WSE 3.0 secure endpoints, security is disabled to keep this sample focused on the custom TCP transport.

    4. Drücken Sie F5, um TcpSyncStockService zu starten.Press F5 to start the TcpSyncStockService. Der Dienst wird in einem neuen Konsolenfenster gestartet.The service starts in a new console window.

    5. Öffnen Sie dieses TCP-Transportbeispiel in Visual Studio.Open this TCP transport sample in Visual Studio.

    6. Aktualisieren Sie die Variable "hostname" in TestCode.cs so, dass sie mit dem Namen des Computers übereinstimmt, auf dem TcpSyncStockService ausgeführt wird.Update the "hostname" variable in TestCode.cs to match the machine name running the TcpSyncStockService.

    7. Drücken Sie F5, um das TCP-Transportbeispiel zu starten.Press F5 to start the TCP transport sample.

    8. Der TCP-Transporttest-Client wird in einem neuen Konsolenfenster gestartet.The TCP transport test client starts in a new console. Der Client fordert beim Dienst Aktienkurse an und zeigt die Ergebnisse dann in seinem Konsolenfenster an.The client requests stock quotes from the service and then displays the results in its console window.

Siehe auchSee Also