Serviços unidirecionais
O comportamento padrão de uma operação de serviço é o padrão de solicitação-resposta. Em um padrão de solicitação-resposta, o cliente aguarda a mensagem de resposta, mesmo que a operação de serviço seja representada no código como um método void
. Com uma operação unidirecional, apenas uma mensagem é transmitida. O receptor não envia uma mensagem de resposta, nem o remetente espera uma.
Use o padrão de design unidirecional:
Quando o cliente deve chamar operações e não é afetado pelo resultado da operação no nível da operação.
Ao usar NetMsmqBinding ou a classe MsmqIntegrationBinding. (Para obter mais informações sobre esse cenário, consulte Filas no WCF).
Quando uma operação é unidirecional, não há nenhuma mensagem de resposta para levar informações de erro de volta para o cliente. Você pode detectar condições de erro usando recursos da associação subjacente, como sessões confiáveis ou projetando um contrato de serviço duplex que usa duas operações unidirecionais — um contrato unidirecional do cliente para o serviço para chamar a operação de serviço e outro contrato unidirecional entre o serviço e o cliente para que o serviço possa enviar falhas de volta ao cliente usando um retorno de chamada que o cliente implementa.
Para criar um contrato de serviço unidirecional, defina o contrato de serviço, aplique a classe OperationContractAttribute a cada operação e defina a propriedade IsOneWay como true
, conforme mostrado no seguinte código de exemplo.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOneWayCalculator
{
[OperationContract(IsOneWay=true)]
void Add(double n1, double n2);
[OperationContract(IsOneWay = true)]
void Subtract(double n1, double n2);
[OperationContract(IsOneWay = true)]
void Multiply(double n1, double n2);
[OperationContract(IsOneWay = true)]
void Divide(double n1, double n2);
}
Para ver um exemplo completo, confira o exemplo Unidirecional.
Bloqueio de clientes com operações unidirecionais
É importante perceber que, embora alguns aplicativos unidirecionais retornem assim que os dados de saída forem gravados na conexão de rede, em vários cenários, a implementação de uma associação ou de um serviço pode fazer com que um cliente WCF bloqueie usando operações unidirecionais. Em aplicativos cliente WCF, o objeto cliente WCF não retorna até que os dados de saída sejam gravados na conexão de rede. Isso é verdadeiro para todos os padrões de troca de mensagens, incluindo operações unidirecionais; isso significa que qualquer problema ao gravar os dados no transporte impede que o cliente retorne. Dependendo do problema, o resultado pode ser uma exceção ou um atraso no envio de mensagens para o serviço.
Por exemplo, se o transporte não puder encontrar o ponto de extremidade, uma exceção System.ServiceModel.EndpointNotFoundException será lançada sem muito atraso. No entanto, também é possível que o serviço não consiga ler os dados da transmissão por algum motivo, o que impede que a operação de envio de transporte do cliente retorne. Nesses casos, se o período Binding.SendTimeout na associação de transporte do cliente for excedido, um System.TimeoutException será gerado, mas não até que o período de tempo limite tenha sido excedido. Também é possível disparar tantas mensagens em um serviço que o serviço não pode processá-las além de um determinado ponto. Nesse caso, também, o cliente unidirecional bloqueia até que o serviço possa processar as mensagens ou até que uma exceção seja lançada.
Outra variação é a situação em que a propriedade de serviço ServiceBehaviorAttribute.ConcurrencyMode está definida Single e a associação usa sessões. Nesse caso, o dispatcher impõe a ordenação nas mensagens de entrada (um requisito de sessões), o que impede que as mensagens subsequentes sejam lidas fora da rede até que o serviço tenha processado a mensagem anterior para essa sessão. Novamente, o cliente bloqueia, mas a ocorrência de uma exceção depende se o serviço é capaz de processar os dados de espera antes das configurações de tempo limite no cliente.
Você pode atenuar parte desse problema inserindo um buffer entre o objeto cliente e a operação de envio do transporte do cliente. Por exemplo, usar chamadas assíncronas ou usar uma fila de mensagens na memória pode permitir que o objeto cliente retorne rapidamente. Ambas as abordagens podem aumentar a funcionalidade, mas o tamanho do pool de threads e da fila de mensagens ainda impõem limites.
É recomendável, em vez disso, que você examine os vários controles no serviço, bem como no cliente, e teste os cenários do aplicativo para determinar a melhor configuração de ambos os lados. Por exemplo, se o uso de sessões estiver bloqueando o processamento de mensagens em seu serviço, você poderá definir a propriedade ServiceBehaviorAttribute.InstanceContextMode como PerCall para que cada mensagem possa ser processada por uma instância de serviço diferente e definir o ConcurrencyMode como Multiple a fim de permitir que mais de um thread envie mensagens por vez. Outra abordagem é aumentar as cotas de leitura das associações de serviço e cliente.