Sdílet prostřednictvím


Postupy: Povolení streamování

Windows Communication Foundation (WCF) může odesílat zprávy buď pomocí vyrovnávací paměti, nebo streamovaných přenosů. Ve výchozím režimu přenosu do vyrovnávací paměti musí být zpráva zcela doručena, aby ji příjemce mohl přečíst. V režimu přenosu streamování může příjemce začít zpracovávat zprávu před tím, než se zcela doručí. Režim streamování je užitečný, pokud jsou předané informace dlouhé a lze je zpracovat sériově. Režim streamování je také užitečný, pokud je zpráva příliš velká, aby byla zcela uložena do vyrovnávací paměti.

Pokud chcete povolit streamování, definujte OperationContract správně a povolte streamování na úrovni přenosu.

Streamování dat

  1. Pokud chcete streamovat data, OperationContract musí služba splňovat dvě požadavky:

    1. Parametr, který obsahuje data, která se mají streamovat, musí být jediným parametrem v metodě. Pokud je vstupní zpráva například ta, která se má streamovat, musí mít operace přesně jeden vstupní parametr. Podobně platí, že pokud se má streamovat výstupní zpráva, musí mít operace buď přesně jeden výstupní parametr, nebo návratovou hodnotu.

    2. Nejméně jeden z typů parametru a návratová hodnota musí být buď Stream, Messagenebo IXmlSerializable.

    Následuje příklad kontraktu pro streamovaná data.

    [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
    

    Operace GetStream obdrží některá vstupní data uložená do vyrovnávací paměti jako stringvyrovnávací paměť a vrátí Stream, která se streamuje. UploadStream Naopak přebírá Stream (streamovaný) a vrací bool (vyrovnávací paměť). EchoStream přijímá a vrací Stream a je příkladem operace, jejíž vstupní a výstupní zprávy se streamují. GetReversedStream Nakonec nepřijímá žádné vstupy a vrací Stream (streamovaný).

  2. U vazby musí být povolené streamování. TransferMode Nastavíte vlastnost, která může mít jednu z následujících hodnot:

    1. Buffered,

    2. Streamed, která umožňuje streamovat komunikaci v obou směrech.

    3. StreamedRequest, což umožňuje pouze streamování požadavku.

    4. StreamedResponse, což umožňuje streamování pouze odpovědi.

    Zpřístupňuje BasicHttpBinding vlastnost vazby TransferMode , stejně jako NetTcpBinding a NetNamedPipeBinding. Vlastnost TransferMode lze také nastavit pro element vazby přenosu a použít ve vlastní vazbě.

    Následující ukázky ukazují, jak nastavit TransferMode kód a změnit konfigurační soubor. Ukázky také nastaví maxReceivedMessageSize vlastnost na 64 MB, což umístí limit na maximální povolenou velikost zpráv při příjmu. Výchozí hodnota maxReceivedMessageSize je 64 kB, což je obvykle příliš nízké pro scénáře streamování. Nastavte toto nastavení kvóty podle potřeby v závislosti na maximální velikosti zpráv, které vaše aplikace očekává. Všimněte si také, že maxBufferSize řídí maximální velikost uloženou do vyrovnávací paměti a odpovídajícím způsobem ji nastavte.

    1. Následující fragment kódu konfigurace z ukázky ukazuje nastavení TransferMode vlastnosti na streamování u basicHttpBinding vlastní vazby 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. Následující fragment kódu ukazuje nastavení TransferMode vlastnosti streamování na basicHttpBinding vlastní vazbu 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. Následující fragment kódu ukazuje nastavení TransferMode vlastnosti streamování na vlastní vazbu 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. GetStreamOperace a UploadStreamEchoStream všechny se zabývají odesíláním dat přímo ze souboru nebo ukládáním přijatých dat přímo do souboru. Následující kód je určen pro 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
    

Zápis vlastního datového proudu

  1. Chcete-li provést speciální zpracování na každém bloku datového proudu při jejich odesílání nebo přijetí, odvodit vlastní třídu streamu z Stream. Jako příklad vlastního streamu obsahuje následující kód metodu GetReversedStreamReverseStream a třídu.

    GetReversedStreamvytvoří a vrátí novou instanci .ReverseStream Skutečné zpracování probíhá, když systém čte z objektu ReverseStream . Metoda ReverseStream.Read načte blok bajtů z podkladového souboru, vrátí je zpět a vrátí obrácené bajty. Tato metoda nevrátí celý obsah souboru; obrátí jeden blok bajtů najednou. Tento příklad ukazuje, jak můžete provádět zpracování datových proudů při čtení nebo zápisu obsahu ze streamu.

    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
    

Viz také