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

  1. Aby przesyłać strumieniowo dane, OperationContract usługa musi spełniać dwa wymagania:

    1. 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ą.

    2. 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 jako stringbuforowane i zwraca Streamelement , który jest przesyłany strumieniowo. Odwrotnie UploadStream przyjmuje wartość (przesyłaną strumieniowo Stream ) i zwraca bool wartość (buforowaną). EchoStream przyjmuje i zwraca Stream i jest przykładem operacji, której komunikaty wejściowe i wyjściowe są przesyłane strumieniowo. Na koniec nie GetReversedStream przyjmuje żadnych danych wejściowych i zwraca wartość Stream (przesyłana strumieniowo).

  2. 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:

    1. Buffered,

    2. Streamed, który umożliwia komunikację strumieniową w obu kierunkach.

    3. StreamedRequest, który umożliwia przesyłanie strumieniowe tylko żądania.

    4. StreamedResponse, który umożliwia przesyłanie strumieniowe tylko odpowiedzi.

    Właściwość BasicHttpBinding uwidacznia TransferMode w powiązaniu, podobnie jak NetTcpBinding i NetNamedPipeBinding. 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ślna maxReceivedMessageSize 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ć, że maxBufferSize kontroluje maksymalny rozmiar buforowany i odpowiednio ustaw go.

    1. Poniższy fragment kodu konfiguracji z przykładu pokazuje ustawienie TransferMode właściwości przesyłania strumieniowego na basicHttpBinding 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>
      
    2. Poniższy fragment kodu przedstawia ustawienie TransferMode właściwości przesyłania strumieniowego na basicHttpBinding 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
      
    3. 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
      
  3. Operacje GetStream, UploadStreami EchoStream wszystkie dotyczą wysyłania danych bezpośrednio z pliku lub zapisywania odebranych danych bezpośrednio do pliku. Poniższy kod jest przeznaczony dla elementu GetStream.

    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

  1. 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 klasy ReverseStream. Rzeczywiste przetwarzanie odbywa się, gdy system odczytuje z ReverseStream obiektu. Metoda ReverseStream.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
    

Zobacz też