Como: habilitar a transmissão
O WCF (Windows Communication Foundation) pode enviar mensagens usando transferências em buffer ou transmitidas. No modo de transferência em buffer padrão, uma mensagem deve ser entregue completamente antes que um receptor possa lê-la. No modo de transferência de streaming, o receptor pode começar a processar a mensagem antes de ser entregue completamente. O modo de streaming é útil quando as informações passadas são longas e podem ser processadas serialmente. O modo de streaming também é útil quando a mensagem é muito grande para ser totalmente armazenada em buffer.
Para habilitar o streaming, defina OperationContract
adequadamente e habilite o streaming no nível do transporte.
Para transmitir dados
Para transmitir dados, o
OperationContract
do serviço deve atender a dois requisitos: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 for a que será transmitida, a operação deverá ter exatamente um parâmetro de entrada. Da mesma forma, se a mensagem de saída for transmitida, a operação deverá ter exatamente um parâmetro de saída ou um valor retornado.
Pelo menos um dos tipos do parâmetro e do valor de retorno deve ser Stream, Message ou IXmlSerializable.
Veja a seguir 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 operação
GetStream
recebe alguns dados de entrada em buffer como umstring
, que são armazenados em buffer e retornam umStream
, que é transmitido. Por outro lado,UploadStream
recebe umStream
(transmitido) e retorna umbool
(em buffer).EchoStream
usa e retornaStream
e é um exemplo de uma operação cujas mensagens de entrada e saída são transmitidas. Por fim,GetReversedStream
não obtém entradas e retorna umStream
(transmitido).O streaming deve ser habilitado na associação. Você define uma propriedade
TransferMode
, que pode levar um dos seguintes valores:Buffered
,Streamed
, que habilita a comunicação de streaming em ambas as direções.StreamedRequest
, que permite transmitir somente a solicitação.StreamedResponse
, que permite transmitir somente a resposta.
O
BasicHttpBinding
expõe a propriedadeTransferMode
na associação, assim comoNetTcpBinding
eNetNamedPipeBinding
. A propriedadeTransferMode
também pode ser definida no elemento de associaçã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 propriedademaxReceivedMessageSize
como 64 MB, o que coloca um limite no tamanho máximo permitido das mensagens recebidas. OmaxReceivedMessageSize
padrão é 64 KB, que geralmente é muito baixo para cenários de streaming. Defina essa configuração de cota conforme apropriado, dependendo do tamanho máximo das mensagens que seu aplicativo espera receber. Observe também quemaxBufferSize
controla o tamanho máximo que é armazenado em buffer e defina-o adequadamente.O snippet de configuração a seguir do exemplo mostra a configuração da propriedade
TransferMode
para streaming embasicHttpBinding
e em 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>
O snippet de código a seguir mostra a configuração da propriedade
TransferMode
para streaming embasicHttpBinding
e em 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
O snippet de código a seguir mostra a configuração da propriedade
TransferMode
para streaming em uma associação HTTP 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
As operações
GetStream
,UploadStream
eEchoStream
lidam com o envio de dados diretamente de um arquivo ou o salvamento de dados recebidos diretamente em um arquivo. O código a seguir é paraGetStream
.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
Gravando um fluxo personalizado
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 método
GetReversedStream
e uma classeReverseStream
.GetReversedStream
cria e retorna uma nova instância deReverseStream
. O processamento real ocorre conforme o sistema lê a partir do objetoReverseStream
. O métodoReverseStream.Read
lê uma parcela de bytes do arquivo subjacente, inverte-os e retorna os bytes invertidos. Esse método não inverte todo o conteúdo do arquivo; ele inverte uma parcela 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 no 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