Olá a todos.
Vamos falar hoje sobre gerenciamento de instância no WCF e para que você possa entender esse artigo é necessário ter um conhecimento básico em WCF.
Existem três formas de realizar requisições através de um serviço WCF. Essas formas são conhecidas como gerenciamento de instância e ajudam a melhorar o desempenho e a segurança do WCF.
Antes de explicar cada gerenciamento de instância, vou mostrar abaixo o código fonte que vamos utilizar para os exemplos. Lembre-se, é recomendado ter conhecimento em WCF.
Vamos utilizar um projeto Console. Primeiro vamos criar a seguinte Interface:
[ServiceContract]<br /> public interface IContrato<br /> {<br /> [OperationContract]<br /> int Contador();<br /> }Em seguida, uma classe que é herdada dessa Interface com a implementação do método Contador:
[ServiceBehavior]<br /> public class Contrato: IContrato<br /> {<br /> private int _intContador;<br /><br /> public int Contador()<br /> {<br /> return _intContador++;<br /> }<br /> }Em Program.cs, no método Main, digite o seguinte código:
static void Main(string[] args)<br /><br /> {<br /><br /> using (ServiceHost host = new ServiceHost(typeof(Contrato), new Uri[] { new Uri("net.tcp://localhost:9393") }))<br /><br /> {<br /><br /> host.Description.Behaviors.Add(new ServiceMetadataBehavior());<br /><br /><br /><br /> host.AddServiceEndpoint(typeof(IContrato), new NetTcpBinding(), "srv");<br /><br /> host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");<br /><br /><br /><br /> host.Open();<br /><br /> Console.WriteLine("[ O Serviço está rodando ]");<br /><br /> Console.ReadLine();<br /><br /><br /><br /> using (ChannelFactory<IContrato> f = new<br />ChannelFactory<IContrato>(new NetTcpBinding(),<br />"net.tcp://localhost:9393/srv"))<br /><br /> {<br /><br /> var channel = f.CreateChannel();<br /><br /><br /><br /> for (int intContador = 0; intContador < 5; intContador++)<br /><br /> {<br /><br /> Console.WriteLine(channel.Contador().ToString());<br /><br /> }<br /><br /> }<br /><br /><br /><br /> using (ChannelFactory<IContrato> f = new<br />ChannelFactory<IContrato>(new NetTcpBinding(),<br />"net.tcp://localhost:9393/srv"))<br /><br /> {<br /><br /> var channel = f.CreateChannel();<br /><br /><br /><br /> for (int intContador = 0; intContador < 5; intContador++)<br /><br /> {<br /><br /> Console.WriteLine(channel.Contador().ToString());<br /><br /> }<br /><br /> }<br /><br /><br /><br /> Console.ReadLine();<br /><br /> }Para esse exemplo, estou criando o host e a chamada ao serviço em uma única aplicação, isso não é correto em um projeto, mas para um exemplo será útil. Depois de criar o host, crio dois proxy (instância do serviço) que realizaram cinco requisições cada um.
Bem, com esse código pronto, vamos às explicações.
PerSession
Esse é a instância padrão do WCF. Quando a aplicação cliente cria uma proxy, esse proxy irá realizar todas as conexões com o serviço que o cliente chamar, até que o método Close (ou Dispose) seja chamado e o proxy seja encerrado.
Enquanto o proxy não for fechado, todas as alterações feitas nos membros internos do serviço (como em uma propriedade global, como no nosso exemplo em _intContador) serão armazenadas. Caso a aplicação cliente crie dois proxy, cada um deles irá controlar sua memória, não interferindo um proxy no outro.
Como já escrevi, o PerSession é a instância default do WCF, nesse caso não precisamos informá-la quando desejamos utilizar, mas em nosso exemplo vamos especificar. Vamos dizer ao WCF para trabalhar com PerSession na classe do serviço (no nosso exemplo, na classe Contrato), como mostrado abaixo:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]Ao executar nosso exemplo, temos o seguinte resultado:

A propriedade _intContador é incrementada sempre que o proxy é chamado, porém quando o proxy é finalizado e um novo é criado, o _intContador começa do zero (propriedade int por padrão começa com valor zero), pois a instância anterior foi perdida.
PerCall
Diferente do PerSession, o PerCall cria uma nova requisição do proxy, ou seja, quando a operação é finalizada, o proxy é removido da memória. Para utilizarmos o PerCall, precisamos alterar na classe Contador o InstanceContextMode, conforme exemplo abaixo:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]Ao executar nosso exemplo após a alteração, temos o seguinte resultado:

O resultado sempre será zero, porque apesar de realizar N requisições ao serviço, a propriedade _intContador não é incrementada.
Single
Single tem uma maneira diferente de se comportar. Existir apenas uma única instância do proxy que irá servir para todas as requisições, mesmo que o Close ou Dispose sejam chamados ou que um novo objeto proxy seja criado. Para utilizarmos o Single, precisamos alterar na classe Contador o InstanceContextMode, conforme exemplo abaixo.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]Mesmo descartando o primeiro proxy, quando começamos a utilizar o segundo proxy, o _intContador continua sendo incrementando com o valor que foi finalizado pelo primeiro proxy, conforme podemos ver na imagem abaixo:

Você deve estar perguntando é a melhor. Bom, isso depende… ninguém melhor do que você para decidir qual tipo de gerenciamento de instância é a melhor para a sua solução. Só devemos tomar cuidado porque a instância está ligada ao binding, ou seja, nem todos os bindings (como BasicHttpBinding) suportam esse exemplo que implementamos.
O código-fonte desse exemplo está disponível aqui.
Espero que tenham gostado e até a próxima.







