Partilhar via


Como: Ativar o streaming

O Windows Communication Foundation (WCF) pode enviar mensagens usando transferências em buffer ou transmitidas. No modo de transferência em buffer padrão, uma mensagem deve ser completamente entregue antes que um recetor possa lê-la. No modo de transferência de streaming, o recetor pode começar a processar a mensagem antes que ela seja completamente entregue. O modo de streaming é útil quando a informação que é passada é longa e pode ser processada em série. O modo de streaming também é útil quando a mensagem é muito grande para ser totalmente armazenada em buffer.

Para habilitar o streaming, defina o apropriado e habilite o OperationContract streaming no nível de transporte.

Para transmitir dados

  1. Para transmitir dados, o OperationContract para o serviço deve satisfazer dois requisitos:

    1. O parâmetro que contém os dados a serem transmitidos deve ser o único parâmetro no método. Por exemplo, se a mensagem de entrada é a que será transmitida, a operação deve ter exatamente um parâmetro de entrada. Da mesma forma, se a mensagem de saída deve ser transmitida, a operação deve ter exatamente um parâmetro de saída ou um valor de retorno.

    2. Pelo menos um dos tipos do parâmetro e do valor de retorno deve ser Stream, Messageou IXmlSerializable.

    Segue-se um exemplo de um contrato para dados transmitidos.

    [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
    

    A GetStream operação recebe alguns dados de entrada em buffer como um string, que é armazenado em buffer e retorna um Stream, que é transmitido. Por outro lado, UploadStream recebe um Stream (transmitido) e retorna um bool (armazenado em buffer). EchoStream toma e retorna Stream e é um exemplo de uma operação cujas mensagens de entrada e saída são transmitidas. Finalmente, GetReversedStream não recebe entradas e retorna um Stream (transmitido).

  2. O streaming deve ser habilitado na vinculação. Você define uma TransferMode propriedade, que pode ter um dos seguintes valores:

    1. Buffered,

    2. Streamed, que permite a comunicação por streaming em ambos os sentidos.

    3. StreamedRequest, que permite transmitir apenas o pedido.

    4. StreamedResponse, que permite transmitir apenas a resposta.

    O BasicHttpBinding expõe a TransferMode propriedade na vinculação, assim como faz NetTcpBinding e NetNamedPipeBinding. A TransferMode propriedade também pode ser definida no elemento de vinculação de transporte e usada em uma associação personalizada.

    Os exemplos a seguir mostram como definir TransferMode por código e alterando o arquivo de configuração. Os exemplos também definem a maxReceivedMessageSize propriedade para 64 MB, o que coloca um limite no tamanho máximo permitido de mensagens ao receber. O padrão maxReceivedMessageSize é 64 KB, que geralmente é muito baixo para cenários de streaming. Defina essa configuração de cota conforme apropriado, dependendo do tamanho máximo de mensagens que seu aplicativo espera receber. Observe também que maxBufferSize controla o tamanho máximo que é armazenado em buffer e defini-lo adequadamente.

    1. O trecho de configuração a seguir do exemplo mostra a configuração da TransferMode propriedade para streaming na basicHttpBinding e uma associação HTTP personalizada.

      <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. O trecho de código a seguir mostra a configuração da TransferMode propriedade para streaming na basicHttpBinding e uma associação HTTP personalizada.

      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. O trecho de código a seguir mostra a configuração da TransferMode propriedade para streaming em uma associação TCP personalizada.

      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. As operações GetStream, UploadStreame EchoStream todas lidam com o envio de dados diretamente de um arquivo ou salvar dados recebidos diretamente em um arquivo. O código a seguir é para 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
    

Escrevendo um fluxo personalizado

  1. Para fazer processamento especial em cada parte de um fluxo de dados à medida que ele está sendo enviado ou recebido, derive uma classe de fluxo personalizada de Stream. Como exemplo de um fluxo personalizado, o código a seguir contém um GetReversedStream método e uma ReverseStream classe-.

    GetReversedStream cria e retorna uma nova instância do ReverseStream. O processamento real acontece quando o sistema lê do ReverseStream objeto. O ReverseStream.Read método lê um pedaço de bytes do arquivo subjacente, reverte-os e, em seguida, retorna os bytes invertidos. Este método não reverte todo o conteúdo do arquivo; ele reverte um pedaço de bytes de cada vez. Este exemplo mostra como você pode executar o processamento de fluxo à medida que o conteúdo está sendo lido ou gravado a partir do fluxo.

    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
    

Consulte também