Vorgehensweise: Aktivieren des Streamingmodus
Windows Communication Foundation (WCF) kann Nachrichten entweder unter Verwendung des gepufferten Übertragungsmodus oder des Streamingmodus senden. Im voreingestellten gepufferten Übertragungsmodus müssen Nachrichten vollständig übertragen worden sein, bevor sie vom Empfänger gelesen werden können. Im Streamingmodus kann der Empfänger mit der Verarbeitung der Nachricht beginnen, bevor diese vollständig übertragen wurde. Der Streamingmodus ist hilfreich, wenn die zu übergebenden Informationen sehr umfangreich sind und hintereinander verarbeitet werden können. Der Streamingmodus ist auch dann nützlich, wenn eine Nachricht zu groß ist, um als Ganzes gepuffert zu werden.
Um den Streamingmodus zu aktivieren, definieren Sie den OperationContract angemessen, und aktivieren Sie den Streamingmodus auf Transportebene.
So werden Daten im Streamingmodus übertragen
Damit Daten im Streamingmodus übermittelt werden können, muss der OperationContract für den Dienst zwei Anforderungen erfüllen:
Der Parameter, der die zu übermittelten Daten enthält, muss der einzige Parameter der Methode sein. Wenn beispielsweise die Eingabenachricht im Streamingmodus übertragen werden soll, muss der Vorgang genau einen Eingabeparameter haben. Ebenso gilt, wenn die Ausgabenachricht im Streamingmodus übertragen werden soll, muss der Vorgang entweder genau einen Ausgabeparameter oder einen Rückgabewert haben.
Mindestens einer der Parameter bzw. der Rückgabewert muss vom Typ Stream, Message oder IXmlSerializable sein
Das folgende Beispiel enthält einen Vertrag für im Streamingmodus zu übertragende Daten.
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _ Public Interface IStreamingSample <OperationContract()> _ Function GetStream(ByVal data As String) As Stream <OperationContract()> _ Function UploadStream(ByVal stream As Stream) As Boolean <OperationContract()> _ Function EchoStream(ByVal stream As Stream) As Stream <OperationContract()> _ Function GetReversedStream() As Stream End Interface
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")] public interface IStreamingSample { [OperationContract] Stream GetStream(string data); [OperationContract] bool UploadStream(Stream stream); [OperationContract] Stream EchoStream(Stream stream); [OperationContract] Stream GetReversedStream(); }
Der
GetStream
-Vorgang muss gepufferte Eingabedaten des Typsstring
erhalten, die dann gepuffert werden, und er gibt einenStream
-Wert zurück, der im Streamingmodus übertragen wird. Umgekehrt akzeptiertUploadStream
einenStream
-Wert (im Streamingmodus) und gibt einenbool
-Wert (gepuffert) zurück.EchoStream
akzeptiert und gibt einen Wert des TypsStream
zurück und ist ein Beispiel für einen Vorgang, dessen Eingabe- und Ausgabenachrichten im Streamingmodus übermittelt werden.GetReversedStream
akzeptiert keine Eingaben und gibt einenStream
-Wert (im Streamingmodus) zurück.Der Streamingmodus muss für die Bindung aktiviert werden. Sie legen eine TransferMode-Eigenschaft fest, für die die folgenden Werte zulässig sind:
Buffered,
Streamed, womit ein Kommunikationsstream in beide Richtungen ermöglicht wird.
StreamedRequest, womit der Streamingmodus lediglich für die Übertragung der Anforderung aktiviert wird.
StreamedResponse, womit der Streamingmodus lediglich für die Übertragung der Antwort aktiviert wird.
Die BasicHttpBinding-Bindung macht die TransferMode-Eigenschaft für die Bindung verfügbar. Dies gilt ebenso für NetTcpBinding und NetNamedPipeBinding. Die TransferMode-Eigenschaft kann auch für das Transportbindungselement festgelegt und in einer benutzerdefinierten Bindung verwendet werden.
In den folgenden Beispielen wird gezeigt, wie TransferMode im Code und durch Ändern der Konfigurationsdatei festgelegt wird. In beiden Beispielen wird zudem die
maxReceivedMessageSize
-Eigenschaft auf 64 MB festgelegt und damit die maximal zulässige Größe für den Empfang von Nachrichten beschränkt.. Die Standardeinstellung vonmaxReceivedMessageSize
ist 64 KB, was normalerweise zu niedrig für die Verwendung des Streamingmodus ist. Legen Sie diese Größeneinstellung, abhängig von der maximalen Größe der Nachrichten, die von der Anwendung empfangen werden sollen, auf einen geeigneten Wert fest. Beachten Sie außerdem, dass die maxBufferSize-Einstellung die maximale Puffergröße angibt, und legen Sie diese Eigenschaft auf einen angemessenen Wert fest.Der folgende Ausschnitt aus der Konfiguration des Beispiel zeigt, wie die TransferMode-Eigenschaft für basicHttpBinding und eine benutzerdefinierte HTTP-Bindung auf den Streamingmodus festgelegt wird.
<basicHttpBinding> <binding name="HttpStreaming" maxReceivedMessageSize="67108864" transferMode="Streamed"/> </basicHttpBinding> <!-- an example customBinding using Http and streaming--> <customBinding> <binding name="Soap12"> <textMessageEncoding messageVersion="Soap12WSAddressing10" /> <httpTransport transferMode="Streamed" maxReceivedMessageSize="67108864"/> </binding> </customBinding>
Der folgende Codeausschnitt zeigt, wie die TransferMode-Eigenschaft für basicHttpBinding und eine benutzerdefinierte HTTP-Bindung auf den Streamingmodus festgelegt wird.
Public Shared Function CreateStreamingBinding() As Binding Dim b As New BasicHttpBinding() b.TransferMode = TransferMode.Streamed Return b End Function
public static Binding CreateStreamingBinding() { BasicHttpBinding b = new BasicHttpBinding(); b.TransferMode = TransferMode.Streamed; return b; }
Der folgende Codeausschnitt zeigt, wie die TransferMode-Eigenschaft für eine benutzerdefinierte TCP-Bindung auf den Streamingmodus festgelegt wird.
Public Shared Function CreateStreamingBinding() As Binding Dim transport As New TcpTransportBindingElement() transport.TransferMode = TransferMode.Streamed Dim binding As New CustomBinding(New BinaryMessageEncodingBindingElement(), _ transport) Return binding End Function
public static Binding CreateStreamingBinding() { TcpTransportBindingElement transport = new TcpTransportBindingElement(); transport.TransferMode = TransferMode.Streamed; BinaryMessageEncodingBindingElement encoder = new BinaryMessageEncodingBindingElement(); CustomBinding binding = new CustomBinding(encoder, transport); return binding; }
Die Vorgänge
GetStream
,UploadStream
undEchoStream
sind damit befasst, Daten direkt aus einer Datei zu senden oder empfangene Daten direkt in eine Datei auszugeben. Der folgende Code ist fürGetStream
vorgesehenPublic Function GetStream(ByVal data As String) As Stream Implements IStreamingSample.GetStream 'this file path assumes the image is in ' the Service folder and the service is executing ' in service/bin Dim filePath = Path.Combine(System.Environment.CurrentDirectory, ".\..\image.jpg") 'open the file, this could throw an exception '(e.g. if the file is not found) 'having includeExceptionDetailInFaults="True" in config ' would cause this exception to be returned to the client Try Return File.OpenRead(filePath) Catch ex As IOException Console.WriteLine(String.Format("An exception was thrown while trying to open file {0}", filePath)) Console.WriteLine("Exception is: ") Console.WriteLine(ex.ToString()) Throw ex End Try End Function
public Stream GetStream(string data) { //this file path assumes the image is in // the Service folder and the service is executing // in service/bin string filePath = Path.Combine( System.Environment.CurrentDirectory, ".\\..\\image.jpg"); //open the file, this could throw an exception //(e.g. if the file is not found) //having includeExceptionDetailInFaults="True" in config // would cause this exception to be returned to the client try { FileStream imageFile = File.OpenRead(filePath); return imageFile; } catch (IOException ex) { Console.WriteLine( String.Format("An exception was thrown while trying to open file {0}", filePath)); Console.WriteLine("Exception is: "); Console.WriteLine(ex.ToString()); throw ex; } }
Schreiben einer benutzerdefinierten Streamklasse
Wenn jedes Element eines Datenstreams beim Senden oder Empfangen auf eine besondere Weise verarbeitet werden soll, müssen Sie eine benutzerdefinierte Streamklasse von der Stream-Klasse ableiten Der folgende Code enthält als Beispiel für einen benutzerdefinierten Stream die
GetReversedStream
-Methode und dieReverseStream
-Klasse.GetReversedStream
erstellt eine neue Instanz derReverseStream
-Klasse und gibt eine Instanz dieser Klasse zurück. Die tatsächliche Verarbeitung erfolgt, wenn das System Daten aus demReverseStream
-Objekt liest. DieReverseStream.Read
-Methode liest eine Gruppe von Bytes aus der zugrunde liegenden Datei, invertiert die Reihenfolge der Bytes und gibt die invertierten Bytes zurück. Diese Methode invertiert nicht den gesamten Dateiinhalt, sondern jeweils nur eine Gruppe von Bytes. Dieses Beispiel zeigt, wie Daten im Streamingmodus verarbeitet werden, wenn Daten aus dem Stream gelesen oder in den Stream geschrieben werden.Friend Class ReverseStream Inherits Stream Private inStream As FileStream Friend Sub New(ByVal filePath As String) 'opens the file and places a StreamReader around it inStream = File.OpenRead(filePath) End Sub Public Overrides ReadOnly Property CanRead() As Boolean Get Return inStream.CanRead End Get End Property Public Overrides ReadOnly Property CanSeek() As Boolean Get Return False End Get End Property Public Overrides ReadOnly Property CanWrite() As Boolean Get Return False End Get End Property Public Overrides Sub Flush() Throw New Exception("This stream does not support writing.") End Sub Public Overrides ReadOnly Property Length() As Long Get Throw New Exception("This stream does not support the Length property.") End Get End Property Public Overrides Property Position() As Long Get Return inStream.Position End Get Set(ByVal value As Long) Throw New Exception("This stream does not support setting the Position property.") End Set End Property Public Overrides Function Read(ByVal buffer() As Byte, _ ByVal offset As Integer, _ ByVal count As Integer) As Integer Dim countRead = inStream.Read(buffer, _ offset, _ count) ReverseBuffer(buffer, _ offset, _ countRead) Return countRead End Function Public Overrides Function Seek(ByVal offset As Long, _ ByVal origin As SeekOrigin) As Long Throw New Exception("This stream does not support seeking.") End Function Public Overrides Sub SetLength(ByVal value As Long) Throw New Exception("This stream does not support setting the Length.") End Sub Public Overrides Sub Write(ByVal buffer() As Byte, _ ByVal offset As Integer, _ ByVal count As Integer) Throw New Exception("This stream does not support writing.") End Sub Public Overrides Sub Close() inStream.Close() MyBase.Close() End Sub Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) inStream.Dispose() MyBase.Dispose(disposing) End Sub Private Sub ReverseBuffer(ByVal buffer() As Byte, _ ByVal offset As Integer, _ ByVal count As Integer) Dim i = offset Dim j = offset + count - 1 Do While i < j Dim currenti = buffer(i) buffer(i) = buffer(j) buffer(j) = currenti i += 1 j -= 1 Loop End Sub End Class
class ReverseStream : Stream { FileStream inStream; internal ReverseStream(string filePath) { //opens the file and places a StreamReader around it inStream = File.OpenRead(filePath); } public override bool CanRead { get { return inStream.CanRead; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return false; } } public override void Flush() { throw new Exception("This stream does not support writing."); } public override long Length { get { throw new Exception("This stream does not support the Length property."); } } public override long Position { get { return inStream.Position; } set { throw new Exception("This stream does not support setting the Position property."); } } public override int Read(byte[] buffer, int offset, int count) { int countRead = inStream.Read(buffer, offset, count); ReverseBuffer(buffer, offset, countRead); return countRead; } public override long Seek(long offset, SeekOrigin origin) { throw new Exception("This stream does not support seeking."); } public override void SetLength(long value) { throw new Exception("This stream does not support setting the Length."); } public override void Write(byte[] buffer, int offset, int count) { throw new Exception("This stream does not support writing."); } public override void Close() { inStream.Close(); base.Close(); } protected override void Dispose(bool disposing) { inStream.Dispose(); base.Dispose(disposing); } void ReverseBuffer(byte[] buffer, int offset, int count) { int i, j; for (i = offset, j = offset + count - 1; i < j; i++, j--) { byte currenti = buffer[i]; buffer[i] = buffer[j]; buffer[j] = currenti; } } }