Instrukcje: Włączanie przesyłania strumieniowego
Program Windows Communication Foundation (WCF) może wysyłać komunikaty przy użyciu buforowanych lub przesyłanych strumieniowo transferów. W domyślnym trybie buforowanego transferu komunikat musi zostać całkowicie dostarczony, zanim odbiorca będzie mógł go odczytać. W trybie transferu strumieniowego odbiornik może rozpocząć przetwarzanie komunikatu, zanim zostanie całkowicie dostarczony. Tryb przesyłania strumieniowego jest przydatny, gdy przekazywane informacje są długie i mogą być przetwarzane szeregowo. Tryb przesyłania strumieniowego jest również przydatny, gdy komunikat jest zbyt duży, aby był całkowicie buforowany.
Aby włączyć przesyłanie strumieniowe, zdefiniuj OperationContract
odpowiednio i włącz przesyłanie strumieniowe na poziomie transportu.
Przesyłanie strumieniowe danych
Aby przesyłać strumieniowo dane,
OperationContract
usługa musi spełniać dwa wymagania:Parametr, który przechowuje dane do przesyłania strumieniowego, musi być jedynym parametrem w metodzie . Jeśli na przykład komunikat wejściowy jest przesyłany strumieniowo, operacja musi mieć dokładnie jeden parametr wejściowy. Podobnie, jeśli komunikat wyjściowy ma być przesyłany strumieniowo, operacja musi mieć dokładnie jeden parametr wyjściowy lub wartość zwracaną.
Co najmniej jeden z typów parametru i zwracanej wartości musi mieć wartość Stream, Messagelub IXmlSerializable.
Poniżej przedstawiono przykład kontraktu dla przesyłanych strumieniowo danych.
[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(); }
<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
Operacja
GetStream
odbiera buforowane dane wejściowe jakostring
buforowane i zwracaStream
element , który jest przesyłany strumieniowo. OdwrotnieUploadStream
przyjmuje wartość (przesyłaną strumieniowoStream
) i zwracabool
wartość (buforowaną).EchoStream
przyjmuje i zwracaStream
i jest przykładem operacji, której komunikaty wejściowe i wyjściowe są przesyłane strumieniowo. Na koniec nieGetReversedStream
przyjmuje żadnych danych wejściowych i zwraca wartośćStream
(przesyłana strumieniowo).Przesyłanie strumieniowe musi być włączone w powiązaniu. Należy ustawić
TransferMode
właściwość , która może przyjmować jedną z następujących wartości:Buffered
,Streamed
, który umożliwia komunikację strumieniową w obu kierunkach.StreamedRequest
, który umożliwia przesyłanie strumieniowe tylko żądania.StreamedResponse
, który umożliwia przesyłanie strumieniowe tylko odpowiedzi.
Właściwość
BasicHttpBinding
uwidaczniaTransferMode
w powiązaniu, podobnie jakNetTcpBinding
iNetNamedPipeBinding
. WłaściwośćTransferMode
można również ustawić dla elementu powiązania transportu i użyć w powiązaniu niestandardowym.W poniższych przykładach pokazano, jak ustawić kod
TransferMode
i zmieniając plik konfiguracji. Oba przykłady ustawiająmaxReceivedMessageSize
również właściwość na 64 MB, co powoduje ograniczenie maksymalnego dozwolonego rozmiaru komunikatów odbieranych. Wartość domyślnamaxReceivedMessageSize
to 64 KB, która zwykle jest zbyt mała w przypadku scenariuszy przesyłania strumieniowego. Ustaw to ustawienie limitu przydziału zgodnie z potrzebami w zależności od maksymalnego rozmiaru komunikatów, które oczekuje aplikacja. Należy również pamiętać, żemaxBufferSize
kontroluje maksymalny rozmiar buforowany i odpowiednio ustaw go.Poniższy fragment kodu konfiguracji z przykładu pokazuje ustawienie
TransferMode
właściwości przesyłania strumieniowego nabasicHttpBinding
obiekcie i niestandardowe powiązanie HTTP.<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>
Poniższy fragment kodu przedstawia ustawienie
TransferMode
właściwości przesyłania strumieniowego nabasicHttpBinding
obiekcie i niestandardowe powiązanie HTTP.public static Binding CreateStreamingBinding() { BasicHttpBinding b = new BasicHttpBinding(); b.TransferMode = TransferMode.Streamed; return b; }
Public Shared Function CreateStreamingBinding() As Binding Dim b As New BasicHttpBinding() b.TransferMode = TransferMode.Streamed Return b End Function
Poniższy fragment kodu pokazuje ustawienie
TransferMode
właściwości przesyłania strumieniowego na niestandardowe powiązanie TCP.public static Binding CreateStreamingBinding() { TcpTransportBindingElement transport = new TcpTransportBindingElement(); transport.TransferMode = TransferMode.Streamed; BinaryMessageEncodingBindingElement encoder = new BinaryMessageEncodingBindingElement(); CustomBinding binding = new CustomBinding(encoder, transport); return binding; }
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
Operacje
GetStream
,UploadStream
iEchoStream
wszystkie dotyczą wysyłania danych bezpośrednio z pliku lub zapisywania odebranych danych bezpośrednio do pliku. Poniższy kod jest przeznaczony dla elementuGetStream
.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; } }
Public 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
Pisanie strumienia niestandardowego
Aby wykonać specjalne przetwarzanie dla każdego fragmentu strumienia danych w miarę wysyłania lub odbierania, utwórz niestandardową klasę strumienia z Streamklasy . Jako przykład strumienia niestandardowego poniższy kod zawiera metodę
GetReversedStream
i klasęReverseStream
.GetReversedStream
tworzy i zwraca nowe wystąpienie klasyReverseStream
. Rzeczywiste przetwarzanie odbywa się, gdy system odczytuje zReverseStream
obiektu. MetodaReverseStream.Read
odczytuje fragment bajtów z pliku bazowego, odwraca je, a następnie zwraca odwrócone bajty. Ta metoda nie odwraca całej zawartości pliku; odwraca jeden fragment bajtów naraz. W tym przykładzie pokazano, jak można wykonywać przetwarzanie strumienia, ponieważ zawartość jest odczytywana lub zapisywana ze strumienia.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; } } }
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