SegmentierungskanalChunking Channel

Beim Senden großer Nachrichten mithilfe von Windows Communication Foundation (WCF), ist es häufig wünschenswert, um die Menge des zur Pufferung dieser Nachrichten verwendete Arbeitsspeicher begrenzen.When sending large messages using Windows Communication Foundation (WCF), it is often desirable to limit the amount of memory used to buffer those messages. Eine mögliche Lösung besteht im Streamen des Nachrichtentexts (vorausgesetzt, der größte Teil der Daten befindet sich dort).One possible solution is to stream the message body (assuming the bulk of the data is in the body). Einige Protokolle erfordern jedoch die Pufferung der Nachricht als Ganzes.However some protocols require buffering of the entire message. Zuverlässiges Messaging und Sicherheit sind zwei solche Beispiele.Reliable messaging and security are two such examples. Eine weitere mögliche Lösung besteht darin, die große Nachricht in kleinere Nachrichten zu teilen, so genannte Segmente, diese Segmente jeweils einzeln zu senden und dann auf der Empfängerseite die große Nachricht wiederherzustellen.Another possible solution is to divide up the large message into smaller messages called chunks, send those chunks one chunk at a time, and reconstitute the large message on the receiving side. Die Anwendung selbst könnte diese Segmentierung und Desegmentierung vornehmen, oder es könnte alternativ ein benutzerdefinierter Kanal dafür verwendet werden.The application itself could do this chunking and de-chunking or it could use a custom channel to do it. Das Beispiel für den Segmentierungskanal zeigt, wie mit einem benutzerdefinierten Protokollkanal oder Mehrschicht-Kanal das Segmentieren und Desegmentieren beliebig großer Nachrichten vorgenommen werden kann.The chunking channel sample shows how a custom protocol or layered channel can be used to do chunking and de-chunking of arbitrarily large messages.

Die Segmentierung sollte stets nur dann eingesetzt werden, wenn die gesamte Nachricht, die gesendet werden soll, erstellt wurde.Chunking should always be employed only after the entire message to be sent has been constructed. Ein Segmentierungskanal sollte immer unter einem Sicherheitskanal und einem zuverlässigen Sitzungskanal angeordnet sein.A chunking channel should always be layered below a security channel and a reliable session channel.

Hinweis

Die Setupprozedur und die Buildanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.The setup procedure and build instructions for this sample are located at the end of this topic.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, fahren Sie mit Windows Communication Foundation (WCF) und Windows Workflow Foundation (WF) Samples for .NET Framework 4 aller Windows Communication Foundation (WCF) herunterladen und WFWF Beispiele.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Extensibility\Channels\ChunkingChannel

Segmentierungskanal   Voraussetzungen und EinschränkungenChunking Channel Assumptions and Limitations

NachrichtenstrukturMessage Structure

Der Segmentierungskanal geht bei zu segmentierenden Nachrichten von folgender Nachrichtenstruktur aus:The chunking channel assumes the following message structure for messages to be chunked:

<soap:Envelope ...>  
  <!-- headers -->  
  <soap:Body>  
    <operationElement>  
      <paramElement>data to be chunked</paramElement>  
    </operationElement>  
  </soap:Body>  
</soap:Envelope>  

Bei Verwendung von ServiceModel erfüllen Vertragsvorgänge mit 1 Eingabeparameter diese Nachrichtenform bei ihrer Eingabenachricht.When using the ServiceModel, contract operations that have 1 input parameter comply with this shape of message for their input message. Ebenso erfüllen Vertragsvorgänge mit 1 Ausgabeparameter bzw. Rückgabewert diese Nachrichtenform bei ihrer Ausgabenachricht.Similarly, contract operations that have 1 output parameter or return value comply with this shape of message for their output message. Es folgen Beispiele für solche Vorgänge:The following are examples of such operations:

[ServiceContract]  
interface ITestService  
{  
    [OperationContract]  
    Stream EchoStream(Stream stream);  

    [OperationContract]  
    Stream DownloadStream();  

    [OperationContract(IsOneWay = true)]  
    void UploadStream(Stream stream);  
}  

SitzungenSessions

Der Segmentierungskanal erfordert, dass Nachrichten genau einmal zugestellt werden, und zwar in geordneter Zustellung von Einzelnachrichten (Segmenten).The chunking channel requires messages to be delivered exactly once, in ordered delivery of messages (chunks). Dies bedeutet, dass der zugrunde liegende Kanalstapel sitzungsbasiert sein muss.This means the underlying channel stack must be sessionful. Sitzungen können vom Transport bereitgestellt werden (z. B. TCP-Transport) oder durch einen sitzungsbasierten Protokollkanal (z. B. ReliableSession-Kanal).Sessions can be provided by the transport (for example, TCP transport) or by a sessionful protocol channel (for example, ReliableSession channel).

Asynchrones Senden und EmpfangenAsynchronous Send and Receive

Asynchrone Methoden zum Senden und Empfangen sind in dieser Version des Segmentierungskanalbeispiels nicht implementiert.Asynchronous send and receive methods are not implemented in this version of the chunking channel sample.

SegmentierungsprotokollChunking Protocol

Der Segmentierungskanal definiert ein Protokoll, das den Start und das Ende einer Segmentreihe sowie die laufende Nummer jedes Segments angibt.The chunking channel defines a protocol that indicates the start and end of a series of chunks as well as the sequence number of each chunk. Die folgenden drei Beispielnachrichten veranschaulichen die Start-, Segmentierungs- und Endnachricht mit Kommentaren, in denen jeweils die wichtigsten Aspekte der einzelnen Elemente beschrieben werden.The following three example messages demonstrate the start, chunk and end messages with comments that describe the key aspects of each.

StartnachrichtStart Message

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"   
            xmlns:s="http://www.w3.org/2003/05/soap-envelope">  
  <s:Header>  
<!—Original message action is replaced with a chunking-specific action. -->  
    <a:Action s:mustUnderstand="1">http://samples.microsoft.com/chunkingAction</a:Action>  
<!--  
Original message is assigned a unique id that is transmitted   
in a MessageId header. Note that this is different from the WS-Addressing MessageId header.  
-->  
    <MessageId s:mustUnderstand="1" xmlns="http://samples.microsoft.com/chunking">  
53f183ee-04aa-44a0-b8d3-e45224563109  
</MessageId>  
<!--  
ChunkingStart header signals the start of a chunked message.  
-->  
    <ChunkingStart s:mustUnderstand="1" i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://samples.microsoft.com/chunking" />  
<!--  
Original message action is transmitted in OriginalAction.  
This is required to re-create the original message on the other side.  
-->  
    <OriginalAction xmlns="http://samples.microsoft.com/chunking">  
http://tempuri.org/ITestService/EchoStream  
    </OriginalAction>  
   <!--  
    All original message headers are included here.  
   -->  
  </s:Header>  
  <s:Body>  
<!--  
Chunking assumes this structure of Body content:  
<element>  
  <childelement>large data to be chunked<childelement>  
</element>  
The start message contains just <element> and <childelement> without  
the data to be chunked.  
-->  
    <EchoStream xmlns="http://tempuri.org/">  
      <stream />  
    </EchoStream>  
  </s:Body>  
</s:Envelope>  

SegmentierungsnachrichtChunk Message

<s:Envelope   
  xmlns:a="http://www.w3.org/2005/08/addressing"   
  xmlns:s="http://www.w3.org/2003/05/soap-envelope">  
  <s:Header>  
   <!--  
    All chunking protocol messages have this action.  
   -->  
    <a:Action s:mustUnderstand="1">  
      http://samples.microsoft.com/chunkingAction  
    </a:Action>  
<!--  
Same as MessageId in the start message. The GUID indicates which original message this chunk belongs to.  
-->  
    <MessageId s:mustUnderstand="1"   
               xmlns="http://samples.microsoft.com/chunking">  
      53f183ee-04aa-44a0-b8d3-e45224563109  
    </MessageId>  
<!--  
The sequence number of the chunk.  
This number restarts at 1 with each new sequence of chunks.  
-->  
    <ChunkNumber s:mustUnderstand="1"   
                 xmlns="http://samples.microsoft.com/chunking">  
      1096  
    </ChunkNumber>  
  </s:Header>  
  <s:Body>  
<!--  
The chunked data is wrapped in a chunk element.  
The encoding of this data (and the entire message)   
depends on the encoder used. The chunking channel does not mandate an encoding.  
-->  
    <chunk xmlns="http://samples.microsoft.com/chunking">  
kfSr2QcBlkHTvQ==  
    </chunk>  
  </s:Body>  
</s:Envelope>  

EndnachrichtEnd Message

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"   
            xmlns:s="http://www.w3.org/2003/05/soap-envelope">  
  <s:Header>  
    <a:Action s:mustUnderstand="1">  
      http://samples.microsoft.com/chunkingAction  
    </a:Action>  
<!--  
Same as MessageId in the start message. The GUID indicates which original message this chunk belongs to.  
-->  
    <MessageId s:mustUnderstand="1"   
               xmlns="http://samples.microsoft.com/chunking">  
      53f183ee-04aa-44a0-b8d3-e45224563109  
    </MessageId>  
<!--  
ChunkingEnd header signals the end of a chunk sequence.  
-->  
    <ChunkingEnd s:mustUnderstand="1" i:nil="true"   
                 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"   
                 xmlns="http://samples.microsoft.com/chunking" />  
<!--  
ChunkingEnd messages have a sequence number.  
-->  
    <ChunkNumber s:mustUnderstand="1"   
                 xmlns="http://samples.microsoft.com/chunking">  
      79  
    </ChunkNumber>  
  </s:Header>  
  <s:Body>  
<!--  
The ChunkingEnd message has the same <element><childelement> structure  
as the ChunkingStart message.  
-->  
    <EchoStream xmlns="http://tempuri.org/">  
      <stream />  
    </EchoStream>  
  </s:Body>  
</s:Envelope>  

SegmentierungskanalarchitekturChunking Channel Architecture

Der Segmentierungskanal ist ein IDuplexSessionChannel, der im Allgemeinen der typischen Kanalarchitektur folgt.The chunking channel is an IDuplexSessionChannel that, at a high level, follows the typical channel architecture. Es gibt ein ChunkingBindingElement, das eine ChunkingChannelFactory und einen ChunkingChannelListener erstellen kann.There is a ChunkingBindingElement that can build a ChunkingChannelFactory and a ChunkingChannelListener. ChunkingChannelFactory erstellt auf Anforderung Instanzen von ChunkingChannel.The ChunkingChannelFactory creates instances of ChunkingChannel when it is asked to. ChunkingChannelListener erstellt Instanzen von ChunkingChannel, wenn ein neuer innerer Kanal akzeptiert wird.The ChunkingChannelListener creates instances of ChunkingChannel when a new inner channel is accepted. Der ChunkingChannel selbst ist für das Senden und Empfangen von Nachrichten verantwortlich.The ChunkingChannel itself is responsible for sending and receiving messages.

Eine Ebene tiefer beruht ChunkingChannel für die Implementierung des Segmentierungsprotokolls auf mehreren Komponenten.At the next level down, ChunkingChannel relies on several components to implement the chunking protocol. Auf der Senderseite verwendet der Kanal einen benutzerdefinierten XmlDictionaryWriter, den so genannten ChunkingWriter, der die eigentliche Segmentierung durchführt.On the send side, the channel uses a custom XmlDictionaryWriter called ChunkingWriter that does the actual chunking. ChunkingWriter verwendet den inneren Kanal direkt zum Senden von Segmenten.ChunkingWriter uses the inner channel directly to send chunks. Durch die Verwendung eines benutzerdefinierten XmlDictionaryWriter können Segmente versendet werden, während der große Text der ursprünglichen Nachricht geschrieben wird.Using a custom XmlDictionaryWriter allows us to send out chunks as the large body of the original message is being written. Dies bedeutet, dass nicht die gesamte ursprüngliche Nachricht gepuffert wird.This means we do not buffer the entire original message.

SegmentierungskanalChunking Channel

Auf der Empfängerseite ruft ChunkingChannel Nachrichten aus dem inneren Kanal ab und gibt sie an einen benutzerdefinierten XmlDictionaryReader, den so genannten ChunkingReader weiter, der die ursprüngliche Nachricht wieder aus den eingehenden Segmenten zusammensetzt.On the receive side, ChunkingChannel pulls messages from the inner channel and hands them to a custom XmlDictionaryReader called ChunkingReader, which reconstitutes the original message from the incoming chunks. ChunkingChannel bindet diesen ChunkingReader in einer benutzerdefinierten Message-Implementierung, der so genannten ChunkingMessage, ein und gibt diese Nachricht an die darüberliegende Schicht zurück.ChunkingChannel wraps this ChunkingReader in a custom Message implementation called ChunkingMessage and returns this message to the layer above. Diese Kombination aus ChunkingReader und ChunkingMessage ermöglicht die Desegmentierung des ursprünglichen Nachrichtentexts, während dieser von der darüberliegenden Schicht gelesen wird. Es ist also nicht erforderlich, den gesamten Text der ursprünglichen Nachricht zu puffern.This combination of ChunkingReader and ChunkingMessage allows us to de-chunk the original message body as it is being read by the layer above instead of having to buffer the entire original message body. ChunkingReader enthält eine Warteschlange, in der die eingehenden Segmente bis zu der maximal konfigurierbaren Anzahl gepufferter Segmente gepuffert werden.ChunkingReader has a queue where it buffers incoming chunks up to a maximum configurable number of buffered chunks. Wenn diese Obergrenze erreicht ist, wartet der Leser, bis Nachrichten durch die darüberliegende Schicht aus der Warteschlange abfließen (d. h. einfach durch Lesen aus dem ursprünglichen Nachrichtentext) oder bis das maximale Empfangs-Timeout erreicht ist.When this maximum limit is reached, the reader waits for messages to be drained from the queue by the layer above (that is, by just reading from the original message body) or until the maximum receive timeout is reached.

SegmentierungskanalChunking Channel

Programmierungsmodell für die SegmentierungChunking Programming Model

Dienstentwickler können angeben, welche Nachrichten segmentiert werden sollen, indem sie das Attribut ChunkingBehavior auf Vorgänge innerhalb des Vertrags anwenden.Service developers can specify which messages are to be chunked by applying the ChunkingBehavior attribute to operations within the contract. Das Attribut macht eine AppliesTo-Eigenschaft verfügbar, mit der der Entwickler angeben kann, ob sich die Segmentierung auf die Eingabenachricht, die Ausgabenachricht oder auf beides bezieht.The attribute exposes an AppliesTo property that allows the developer to specify whether chunking applies to the input message, the output message or both. Im folgenden Beispiel wird die Verwendung des ChunkingBehavior-Attributs veranschaulicht.The following example shows the usage of ChunkingBehavior attribute:

[ServiceContract]  
interface ITestService  
{  
    [OperationContract]  
    [ChunkingBehavior(ChunkingAppliesTo.Both)]  
    Stream EchoStream(Stream stream);  

    [OperationContract]  
    [ChunkingBehavior(ChunkingAppliesTo.OutMessage)]  
    Stream DownloadStream();  

    [OperationContract(IsOneWay=true)]  
    [ChunkingBehavior(ChunkingAppliesTo.InMessage)]  
    void UploadStream(Stream stream);  

}  

Aus diesem Programmierungsmodell kompiliert ChunkingBindingElement eine Liste von Aktions-URIs, die die zu segmentierenden Nachrichten identifizieren.From this programming model, the ChunkingBindingElement compiles a list of action URIs that identify messages to be chunked. Die Aktion der einzelnen ausgehenden Nachrichten wird mit dieser Liste verglichen, um zu bestimmen, ob die Nachricht segmentiert oder direkt gesendet werden soll.The action of each outgoing message is compared against this list to determine if the message should be chunked or sent directly.

Implementieren des SendevorgangsImplementing the Send Operation

Allgemein gesagt überprüft der Sendevorgang zunächst, ob die ausgehende Nachricht segmentiert werden muss, und falls nicht, sendet sie die Nachricht direkt über den inneren Kanal.At a high level, the Send operation first checks whether the outgoing message must be chunked and, if not, sends the message directly using the inner channel.

Wenn die Nachricht segmentiert werden muss, erstellt Send einen neuen ChunkingWriter und ruft WriteBodyContents in der ausgehenden Nachricht auf, der sie diesen ChunkingWriter übergibt.If the message must be chunked, Send creates a new ChunkingWriter and calls WriteBodyContents on the outgoing message passing it this ChunkingWriter. Der ChunkingWriter nimmt dann die Nachrichtensegmentierung vor (dazu gehört das Kopieren der ursprünglichen Nachrichtenheaders in die Startsegmentnachricht) und sendet Segmente über den inneren Kanal.The ChunkingWriter then does the message chunking (including copying original message headers to the start chunk message) and sends chunks using the inner channel.

Hier einige Details, die beachtet werden sollten:A few details worth noting:

  • Send ruft zunächst ThrowIfDisposedOrNotOpened auf, um sicherzustellen, dass CommunicationState geöffnet ist.Send first calls ThrowIfDisposedOrNotOpened to ensure the CommunicationState is opened.

  • Das Senden wird synchronisiert, sodass für die einzelnen Sitzungen jeweils nicht mehrere Nachrichten gleichzeitig gesendet werden können.Sending is synchronized so that only one message can be sent at a time for each session. Es gibt einen ManualResetEvent namens sendingDone, der zurückgesetzt wird, wenn eine segmentierte Nachricht gesendet wird.There is a ManualResetEvent named sendingDone that is reset when a chunked message is being sent. Sobald die Endsegmentnachricht gesendet wurde, ist dieses Ereignis festgelegt.Once the end chunk message is sent, this event is set. Die Send-Methode wartet, bis dieses Ereignis festgelegt ist, bevor sie versucht, die ausgehende Nachricht zu senden.The Send method waits for this event to be set before it tries to send the outgoing message.

  • Send sperrt CommunicationObject.ThisLock, um Änderungen am synchronisierten Zustand während des Sendens zu vermeiden.Send locks the CommunicationObject.ThisLock to prevent synchronized state changes while sending. Weitere Informationen zu CommunicationObject-Zuständen und den Zustandsautomaten finden Sie in der CommunicationObject-Dokumentation.See the CommunicationObject documentation for more information about CommunicationObject states and state machine.

  • Der an Send übergebene Timeout dient als Timeout für den gesamten Sendevorgang, der das Senden aller Segmente umfasst.The timeout passed to Send is used as the timeout for the entire send operation which includes sending all of the chunks.

  • Der benutzerdefinierte XmlDictionaryWriter-Entwurf wurde ausgewählt, um zu vermeiden, dass der gesamte Text der ursprünglichen Nachricht gepuffert wird.The custom XmlDictionaryWriter design was chosen to avoid buffering the entire original message body. Wenn mithilfe von XmlDictionaryReader ein message.GetReaderAtBodyContents für den Text verwendet würde, würde der gesamte Nachrichtentext gepuffert.If we were to get an XmlDictionaryReader on the body using message.GetReaderAtBodyContents the entire body would be buffered. Stattdessen haben wir einen benutzerdefinierten XmlDictionaryWriter, der an message.WriteBodyContents übergeben wird.Instead, we have a custom XmlDictionaryWriter that is passed to message.WriteBodyContents. Wenn die Nachricht WriteBase64 beim Writer aufruft, fasst der Writer Segmente zu Nachrichten zusammen und sendet sie über den inneren Kanal.As the message calls WriteBase64 on the writer, the writer packages up chunks into messages and sends them using the inner channel. WriteBase64 blockiert, bis das Segment gesendet wurde.WriteBase64 blocks until the chunk is sent.

Implementieren des Empfangsvorgangs (Receive)Implementing the Receive Operation

Allgemein gesagt stellt der Empfangsvorgang (Receive) zunächst sicher, dass die eingehende Nachricht nicht null und dass ihre Aktion ChunkingAction lautet.At a high level, the Receive operation first checks that the incoming message is not null and that its action is the ChunkingAction. Wenn sie nicht beide Kriterien erfüllt, wird die Nachricht unverändert von Receive zurückgegeben.If it does not meet both criteria, the message is returned unchanged from Receive. Andernfalls erstellt Receive einen neuen ChunkingReader und eine neue ChunkingMessage, die ihn umgibt (durch Aufrufen von GetNewChunkingMessage).Otherwise, Receive creates a new ChunkingReader and a new ChunkingMessage wrapped around it (by calling GetNewChunkingMessage). Vor der Rückgabe dieser neuen ChunkingMessage führt Receive mithilfe eines Threadpool-Threads ReceiveChunkLoop aus, wodurch wiederum innerChannel.Receive in einer Schleife aufgerufen wird und Segmente an ChunkingReader übergeben werden, bis die Endsegmentnachricht empfangen oder der Receive-Timeout erreicht wird.Before returning that new ChunkingMessage, Receive uses a threadpool thread to execute ReceiveChunkLoop, which calls innerChannel.Receive in a loop and hands off chunks to the ChunkingReader until the end chunk message is received or the receive timeout is hit.

Hier einige Details, die beachtet werden sollten:A few details worth noting:

  • Wie Send ruft auch Receive zunächst ThrowIfDisposedOrNotOepned auf, um sicherzustellen, dass CommunicationState geöffnet ist.Like Send, Receive first calls ThrowIfDisposedOrNotOepned to ensure the CommunicationState is Opened.

  • Auch Receive wird synchronisiert, sodass aus der Sitzung nicht mehrere Nachrichten gleichzeitig empfangen werden können.Receive is also synchronized so that only one message can be received at a time from the session. Dies ist besonders wichtig, da nach dem Empfang einer Startsegmentnachricht davon ausgegangen wird, dass alle anschließend empfangenen Nachrichten Segmente innerhalb dieser neuen Segmentsequenz sind, bis eine Endsegmentnachricht empfangen wird.This is especially important because once a start chunk message is received, all subsequent received messages are expected to be chunks within this new chunk sequence until an end chunk message is received. Receive kann so lange keine Nachrichten mithilfe von Pull aus dem inneren Kanal übertragen, bis alle Segmente, die zu der Nachricht gehören, die momentan wieder aus ihren Segmenten zusammengesetzt wird, empfangen wurden.Receive cannot pull messages from the inner channel until all chunks that belong to the message currently being de-chunked are received. Um dies zu erreichen, verwendet Receive ein ManualResetEvent namens currentMessageCompleted, das beim Empfang der Endsegmentnachricht festgelegt und beim Empfang einer neuen Startsegmentnachricht zurückgesetzt wird.To accomplish this, Receive uses a ManualResetEvent named currentMessageCompleted, which is set when the end chunk message is received and reset when a new start chunk message is received.

  • Im Gegensatz zu Send verhindert Receive während des Empfangs keine Zustandsübergänge bei synchronisierten Zuständen.Unlike Send, Receive does not prevent synchronized state transitions while receiving. So kann beispielsweise Close während des Empfangs aufgerufen werden. Der Vorgang wartet dann, bis der ausstehende Empfang der ursprünglichen Nachricht abgeschlossen bzw. der angegebene Timeoutwert erreicht ist.For example, Close can be called while receiving and waits until the pending receive of the original message is completed or the specified timeout value is reached.

  • Der an Receive übergebene Timeout dient als Timeout für den gesamten Empfangsvorgang, der den Empfang aller Segmente umfasst.The timeout passed to Receive is used as the timeout for the entire receive operation, which includes receiving all of the chunks.

  • Wenn die Schicht, die die Nachricht verwendet, den Nachrichtentext langsamer verwendet als Segmentnachrichten eintreffen, puffert ChunkingReader die eingehenden Segmente bis zu der von ChunkingBindingElement.MaxBufferedChunks angegebenen Obergrenze.If the layer that consumes the message is consuming the message body at a rate lower than the rate of incoming chunk messages, the ChunkingReader buffers those incoming chunks up to the limit specified by ChunkingBindingElement.MaxBufferedChunks. Nachdem dieser Grenzwert erreicht wurde, werden erst dann wieder Segmente mithilfe von Pull aus der unteren Schicht übertragen, wenn entweder ein gepuffertes Segment verwendet oder der Empfangs-Timeout erreicht wurde.Once that limit is reached, no more chunks are pulled from the lower layer until either a buffered chunk is consumed or the receive timeout is reached.

CommunicationObject-ÜberschreibungenCommunicationObject Overrides

OnOpenOnOpen

OnOpen ruft innerChannel.Open auf, um den inneren Kanal zu öffnen.OnOpen calls innerChannel.Open to open the inner channel.

OnCloseOnClose

OnClose legt zuerst stopReceive auf true fest, um zu signalisieren, dass der ausstehendeReceiveChunkLoop beendet werden soll.OnClose first sets stopReceive to true to signal the pending ReceiveChunkLoop to stop. Dann wartet der receiveStopped``ManualResetEvent, dem wird festgelegt, wenn ReceiveChunkLoop beendet.It then waits for the receiveStopped``ManualResetEvent, which is set when ReceiveChunkLoop stops. Angenommen, ReceiveChunkLoop wird innerhalb des angegebenen Timeouts beendet, dann ruft OnClose mit dem restlichen Timeout innerChannel.Close auf.Assuming the ReceiveChunkLoop stops within the specified timeout, OnClose calls innerChannel.Close with the remaining timeout.

OnAbortOnAbort

OnAbort ruft innerChannel.Abort auf, um den inneren Kanal abzubrechen.OnAbort calls innerChannel.Abort to abort the inner channel. Wenn es einen ausstehenden ReceiveChunkLoop gibt, erhält diese eine Ausnahme vom ausstehenden innerChannel.Receive-Aufruf.If there is a pending ReceiveChunkLoop it gets an exception from the pending innerChannel.Receive call.

OnFaultedOnFaulted

Der ChunkingChannel erfordert kein besonderes Verhalten, wenn der Kanal einen Fehler verursacht hat, sodass OnFaulted nicht überschrieben wird.The ChunkingChannel does not require special behavior when the channel is faulted so OnFaulted is not overridden.

Implementieren einer KanalfactoryImplementing Channel Factory

Der ChunkingChannelFactory ist dafür zuständig, Instanzen von ChunkingDuplexSessionChannel zu erstellen und Zustandsübergänge an die innere Kanalfactory weiterzugeben.The ChunkingChannelFactory is responsible for creating instances of ChunkingDuplexSessionChannel and for cascading state transitions to the inner channel factory.

OnCreateChannel verwendet die innere Kanalfactory zur Erstellung eines inneren IDuplexSessionChannel-Kanals.OnCreateChannel uses the inner channel factory to create an IDuplexSessionChannel inner channel. Anschließend erstellt es einen neuen ChunkingDuplexSessionChannel, dem sie beim Empfang diesen inneren Kanal sowie die Liste der zu segmentierenden Nachrichtenaktionen und die maximale Anzahl der zu puffernden Segmente übergibt.It then creates a new ChunkingDuplexSessionChannel passing it this inner channel along with the list of message actions to be chunked and the maximum number of chunks to buffer upon receive. Die Liste der zu segmentierenden Nachrichtenaktionen und die maximale Anzahl der zu puffernden Segmente sind zwei Parameter, die im Konstruktor an ChunkingChannelFactory weitergegeben werden.The list of message actions to be chunked and the maximum number of chunks to buffer are two parameters passed to ChunkingChannelFactory in its constructor. Im Abschnitt über ChunkingBindingElement wird beschrieben, woher diese Werte kommen.The section on ChunkingBindingElement describes where these values come from.

OnOpen, OnClose, OnAbort und ihre asynchronen Entsprechungen rufen die entsprechende Zustandsübergangsmethode in der inneren Kanalfactory auf.The OnOpen, OnClose, OnAbort and their asynchronous equivalents call the corresponding state transition method on the inner channel factory.

Implementieren eines KanallistenersImplementing Channel Listener

Der ChunkingChannelListener ist ein Wrapper um einen inneren Kanallistener.The ChunkingChannelListener is a wrapper around an inner channel listener. Neben dem Delegieren von Aufrufen an diesen inneren Kanallistener besteht seine Hauptaufgabe darin, neue ChunkingDuplexSessionChannels um Kanäle zu legen, die aus dem inneren Kanallistener akzeptiert wurden.Its main function, besides delegate calls to that inner channel listener, is to wrap new ChunkingDuplexSessionChannels around channels accepted from the inner channel listener. Dies erfolgt in OnAcceptChannel und OnEndAcceptChannel.This is done in OnAcceptChannel and OnEndAcceptChannel. Dem neu erstellten ChunkingDuplexSessionChannel wird der innere Kanal, zusammen mit den anderen, bereits beschriebenen Parametern, übergeben.The newly created ChunkingDuplexSessionChannel is passed the inner channel along with the other parameters previously described.

Implementieren von Bindungselement und BindungImplementing Binding Element and Binding

ChunkingBindingElement ist für das Erstellen der ChunkingChannelFactory und des ChunkingChannelListener verantwortlich.ChunkingBindingElement is responsible for creating the ChunkingChannelFactory and ChunkingChannelListener. Die ChunkingBindingElement überprüft, ob T in CanBuildChannelFactory <T > und CanBuildChannelListener <T > ist vom Typ IDuplexSessionChannel (der einzige Kanal, der vom segmentierungskanal unterstützt) und ob die anderen Bindungselemente der Bindung, die dies unterstützen Der Kanaltyp.The ChunkingBindingElement checks whether T in CanBuildChannelFactory<T> and CanBuildChannelListener<T> is of type IDuplexSessionChannel (the only channel supported by the chunking channel) and that the other binding elements in the binding support this channel type.

BuildChannelFactory<T > zunächst sicher, dass der angeforderte Kanaltyp erstellt werden kann, und anschließend eine Liste der ruft zu segmentierenden Nachrichtenaktionen.BuildChannelFactory<T> first checks that the requested channel type can be built and then gets a list of message actions to be chunked. Weitere Informationen finden Sie in folgendem Abschnitt.For more information, see the following section. Anschließend erstellt es einen neuen ChunkingChannelFactory, dem es die innere Kanalfactory (wie aus context.BuildInnerChannelFactory<IDuplexSessionChannel> zurückgegeben), die Liste der Nachrichtenaktionen und die maximale Anzahl der beim Empfang zu puffernden Segmente übergibt.It then creates a new ChunkingChannelFactory passing it the inner channel factory (as returned from context.BuildInnerChannelFactory<IDuplexSessionChannel>), the list of message actions, and the maximum number of chunks to buffer. Die maximale Anzahl an Segmenten stammt aus einer Eigenschaft namens MaxBufferedChunks, die vom ChunkingBindingElement verfügbar gemacht wird.The maximum number of chunks comes from a property called MaxBufferedChunks exposed by the ChunkingBindingElement.

BuildChannelListener<T> hat zum Erstellen von ChunkingChannelListener und zur Übergabe an den inneren Kanallistener eine ähnliche Implementierung.BuildChannelListener<T> has a similar implementation for creating ChunkingChannelListener and passing it the inner channel listener.

In diesem Beispiel ist eine Beispielbindung namens TcpChunkingBinding enthalten.There is an example binding included in this sample named TcpChunkingBinding. Diese Bindung besteht aus zwei Bindungselementen: TcpTransportBindingElement und ChunkingBindingElement.This binding consists of two binding elements: TcpTransportBindingElement and ChunkingBindingElement. Die Bindung macht nicht nur die Eigenschaft MaxBufferedChunks verfügbar, sondern legt auch einige der TcpTransportBindingElement-Eigenschaften fest, wie beispielsweise MaxReceivedMessageSize (wird auf ChunkingUtils.ChunkSize + 100 KB für Header festgelegt).In addition to exposing the MaxBufferedChunks property, the binding also sets some of the TcpTransportBindingElement properties such as MaxReceivedMessageSize (sets it to ChunkingUtils.ChunkSize + 100KB bytes for headers).

TcpChunkingBinding implementiert außerdem IBindingRuntimePreferences und gibt den Wert true aus der ReceiveSynchronously-Methode zurück, was anzeigt, dass nur die synchronen Receive-Aufrufe implementiert werden.TcpChunkingBinding also implements IBindingRuntimePreferences and returns true from the ReceiveSynchronously method indicating that only the synchronous Receive calls are implemented.

Bestimmen der zu segmentierenden NachrichtenDetermining Which Messages To Chunk

Der Segmentierungskanal segmentiert nur die Nachrichten, die über das ChunkingBehavior-Attribut identifiziert wurden.The chunking channel chunks only the messages identified through the ChunkingBehavior attribute. Die ChunkingBehavior-Klasse implementiert IOperationBehavior und wird durch Aufrufen der AddBindingParameter-Methode implementiert.The ChunkingBehavior class implements IOperationBehavior and is implemented by calling the AddBindingParameter method. In dieser Methode untersucht ChunkingBehavior den Wert dieser AppliesTo-Eigenschaft (InMessage, OutMessage oder beides), um zu bestimmen, welche Nachrichten segmentiert werden sollen.In this method, the ChunkingBehavior examines the value of its AppliesTo property (InMessage, OutMessage or both) to determine which messages should be chunked. Anschließend ruft es die Aktion jeder diese Nachrichten ab (aus der Nachrichtenauflistung unter OperationDescription) und fügt sie einer Zeichenfolgenauflistung hinzu, die in einer Instanz von ChunkingBindingParameter enthalten ist.It then gets the action of each of those messages (from the Messages collection on OperationDescription) and adds it to a string collection contained within an instance of ChunkingBindingParameter. Anschließend wird dieser ChunkingBindingParameter der angegebenen BindingParameterCollection hinzugefügt.It then adds this ChunkingBindingParameter to the provided BindingParameterCollection.

Diese BindingParameterCollection wird innerhalb von BindingContext an die einzelnen Bindungselemente in der Bindung übergeben, wenn das betreffende Bindungselement die Kanalfactory oder den Kanallistener erstellt.This BindingParameterCollection is passed inside the BindingContext to each binding element in the binding when that binding element builds the channel factory or the channel listener. Die ChunkingBindingElementder Implementierung von BuildChannelFactory<T> und BuildChannelListener<T> ziehen Sie diesen ChunkingBindingParameter aus der BindingContext’s BindingParameterCollection.The ChunkingBindingElement's implementation of BuildChannelFactory<T> and BuildChannelListener<T> pull this ChunkingBindingParameter out of the BindingContext’s BindingParameterCollection. Die Auflistung der in ChunkingBindingParameter enthaltenen Aktionen wird anschließend an ChunkingChannelFactory oder ChunkingChannelListener übergeben, von wo aus sie wiederum an ChunkingDuplexSessionChannel übergeben wird.The collection of actions contained within the ChunkingBindingParameter is then passed to the ChunkingChannelFactory or ChunkingChannelListener, which in turn passes it to the ChunkingDuplexSessionChannel.

Ausführen des BeispielsRunning the Sample

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

  1. Installieren Sie ASP.NETASP.NET 4.0 mithilfe des folgenden Befehls.Install ASP.NETASP.NET 4.0 using the following command.

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable  
    
  2. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  3. Führen Sie zum Erstellen der Projektmappe die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  4. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

  5. Führen Sie zuerst Service.exe und dann Client.exe aus, und sehen Sie sich die Ausgabe in beiden Konsolenfenstern an.Run Service.exe first, then run Client.exe and watch both console windows for output.

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

Client:Client:

Press enter when service is available  

 > Sent chunk 1 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 2 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 3 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 4 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 5 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 6 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 7 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 8 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 9 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 10 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 1 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 2 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 3 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 4 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 5 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 6 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 7 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 8 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 9 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 < Received chunk 10 of message 5b226ad5-c088-4988-b737-6a565e0563dd  

Server:Server:

Service started, press enter to exit  
 < Received chunk 1 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 2 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 3 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 4 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 5 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 6 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 7 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 8 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 9 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 < Received chunk 10 of message 867c1fd1-d39e-4be1-bc7b-32066d7ced10  
 > Sent chunk 1 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 2 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 3 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 4 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 5 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 6 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 7 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 8 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 9 of message 5b226ad5-c088-4988-b737-6a565e0563dd  
 > Sent chunk 10 of message 5b226ad5-c088-4988-b737-6a565e0563dd  

Siehe auchSee Also