Zona .Net

Refatorando idéias, produzindo conhecimento.

Archive for the ‘Streaming’ Category

Streaming com WCF

leave a comment »

Em alguns serviços existe a necessidade de tráfego de grande volume de dados onde é inviável esperar o recebimento total da mensagem para então ser processada. Por isso no WCF temos a possibilidade de trafegar dados em forma de stream, ou seja, sem a necessidade de aguardar o carregamento completo do objeto na memória para então enviá-lo. Dessa forma o receptor já começa a processar a mensagem antes do termino do envio, aumentando assim a escalabilidade.

Vale ressaltar que essa forma de transferência não esta disponível para todos os bindings, apenas para os seguintes: BasicHttpBinding, NetTcpBinding e NetNamedPipeBinding.

Para implementar tal funcionalidade, lançamos mão da propriedade TransferMode que recebe uma das opções do enumerador de mesmo nome. São elas:

Buffered: A mensagem é carregada totalmente na memória antes de ser enviada ao destinatário. É a configuração padrão para todos os bindings.

Streamed: A mensagem e enviada como um stream, exceto o header que é carregado completamente, não excedendo o MaxBufferSize.

StreamedRequest: Apenas a requisição será enviada como stream, sendo  a resposta coloca em buffer antes do envio.

StreamedResponse: É o inverso do anterior, apenas a resposta será enviada em forma de stream.

Existem algumas regras para uso de stream com WCF, uma delas é que a operações/métodos que compõe o contrato recebam ou retornem uma instancia da classe stream ou uma implementação da interface IXmlSerializable.

Um detalhe a ser observado é que o Header da mensagem será sempre posto em buffer.

Tenha em mente também que ao utilizar stream para ganhar performance você abre mão de alguns recursos como transações, segurança no nível de mensagem, etc.

Veja o contrato de serviço abaixo:

[ServiceContract]
public interface IArquivos
{
   [OperationContract]
   Stream Download(string nomeArquivo);

   [OperationContract]
   bool Upload(Stream arquivo);
}

As operações Upload e Download recebem e devolvem streams respectivamente. Veremos agora a implementação desse contrato:

public class FileService :   IArquivos
{
   public Stream Download(string   nomeArquivo)
   {
      return new FileStream(@"..\Files\"   + nomeArquivo, FileMode.Open);
   }

   public bool Upload(Stream arquivo)
   {
      string nomeArquivo =  "BinFile.bin";
      using (FileStream fs = new   FileStream(@"..\Files\" + nomeArquivo, FileMode.Create))
      {
         byte[] buffer = new   byte[8192];
         int bytesRead = arquivo.Read(buffer,   0, 8192);

         while (bytesRead > 0)
         {
            fs.Write(buffer, 0,   bytesRead);
            bytesRead =   imagem.Read(buffer, 0, 8192);
         }
      }
      return true;
   }
}

Outro detalhe importante é em relação ao controle de fechamento do stream, assumimos que sempre quem recebe deve fechá-lo, já que não sabemos quando o receptor realmente recebeu e processou toda a mensagem. No exemplo acima estamos utilizando o bloco using, que invocará o método dispose do objeto FileStream ao sair do escopo.

Vejamos agora o Host desse serviço:

Em uma aplicação console application, adicione a referencia do projeto do serviço e colocamos o seguinte código no método Main:

using (ServiceHost host =   new ServiceHost(typeof(FileService), new Uri[] { new   Uri("http://localhost:7744") }))
{
   BasicHttpBinding objHttpBinding =   new BasicHttpBinding();
   objHttpBinding.TransferMode =   TransferMode.Streamed;
   objHttpBinding.MaxBufferSize =   3065536;
   objHttpBinding.MaxReceivedMessageSize   = 3065536;

   host.Description.Behaviors.Add(new   ServiceMetadataBehavior() { HttpGetEnabled = true });
   host.AddServiceEndpoint(typeof(IArquivos), objHttpBinding, "arquivos");
   host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(),   "mex");

   host.Open();
   
   Console.ReadLine();
}

No host do serviço eu alterei as propriedades MaxBufferSize e MaxReceivedMessageSize, onde a primeira afeta apenas o que é trafegado no header, que é a única parte da mensagem que utiliza buffer.

Vimos que a implementação de mensagens via stream é bem simples e se usada com cautela pode aumentar a escalabiliade de um serviço WCF, também vimos como o WCF é flexível e consegue um baixo acoplamento entre a implementação do serviço e da sua execução por parte do host.


MVP Logo Leonardo Bruno Lima
Microsoft MVP | MCT | MCTS | MCPD
Attps Informática [http://www.attps.com.br]
+55 (85) 99449511
GMail: lblima.net@gmail.com
Live Mail: lblima_net@hotmail.com
   
Blogs: http://lblima.blogspot.com | https://zonadotnet.wordpress.com

“I do not agree with what you have to say, but I’ll defend to the death your
right to say it.” Voltaire.

Written by Leonardo Bruno Lima

4 de agosto de 2009 at 3:23 am

Publicado em .NET, Streaming, WCF

Tagged with , ,