Diferentes formas da interface de contrato de serviço do WCF

Parece que posso alternar livremente entre as três versões diferentes da mesma API de interface de contrato do WCF, sem violar os clientes:

[ServiceContract] interface IService { // Either synchronous // [OperationContract] // int SomeMethod(int arg); // Or TAP [OperationContract] Task SomeMethodAsync(int arg); // Or APM // [OperationContract(AsyncPattern = true)] // IAsyncResult BeginSomeMethod(int arg, AsyncCallback callback, object state); // int EndSomeMethod(IAsyncResult ar); } 

O aplicativo cliente de teste existente continua funcionando sem qualquer recompilation ou toque. Se eu recompilar o serviço e reimportar sua referência no aplicativo cliente, a definição do WSDL permanecerá a mesma , 1: 1.

Minhas perguntas:

  • É um comportamento legítimo em que posso confiar? Está documentado em algum lugar?

A idéia é converter um conjunto de methods de estilo SomeMethod síncronos em methods de estilo TAP SomeMethodAsync , para usar async/await em sua implementação e assim melhorar a escalabilidade do serviço WCF, sem quebrar clientes existentes.

Além disso, tem havido problemas conhecidos com o dimensionamento de serviços WCF no .NET 3.5 e .NET 4.0. Eles estão documentados no artigo do MSKB “O serviço WCF pode aumentar lentamente sob carga” e o artigo do CodeProject “Ajustando o WCF para criar uma API REST assíncrona altamente escalonável” . Basicamente, não era suficiente implementar as APIs de contrato de serviço como naturalmente assíncronas, o tempo de execução do WCF ainda estava bloqueando o thread de solicitação.

  • Alguém sabe se esse problema foi corrigido para .NET 4.5.x , out-of-the-box? Ou os ajustes adicionais ainda são necessários?

As operações do WCF podem ser definidas usando o TAP síncrono, EAP ou (a partir do .NET 4.5). Do MSDN :

Os clientes podem oferecer ao desenvolvedor qualquer modelo de programação que escolherem, desde que o padrão subjacente de troca de mensagens seja observado. Assim, também, os serviços podem implementar operações de qualquer maneira, desde que o padrão de mensagem especificado seja observado.

Você pode ter todos os 3 padrões em uma única interface de contrato e todos eles se relacionam com a mesma mensagem.

No fio, não há diferença como você executa as operações. O WSDL (que o WCF constrói a partir do ABC, endereço, binding e contrato de cada endpoint) não contém essa informação. É gerado a partir de descrições de operação .

Se você observar a class OperationDescription , que é usada em um ContractDescription , verá que cada operação possui estas propriedades: SyncMethod , BeginMethod , EndMethod e TaskMethod . Ao criar uma descrição, o WCF combinará todos os methods de acordo com o nome da operação em uma única operação. Se houver alguma incompatibilidade entre operações com o mesmo nome em padrões diferentes (por exemplo, parâmetros diferentes), o WCF lançaria uma exceção detalhando exatamente o que está errado. O WCF assume automaticamente o sufixo “Async” (opcional) para os methods baseados em tarefas e o prefixo Begin / End para o APM.

O lado do cliente e do servidor são completamente não relacionados neste sentido. O utilitário que gera classs de proxy do WSDL ( svcutil ) pode construir proxies para qualquer padrão de execução. Não precisa nem mesmo ser um serviço WCF.

No lado do servidor, se mais de um padrão for implementado, o WCF usará apenas um na seguinte ordem de precedência: Tarefa, Sincronização e APM. Isso está documentado em algum lugar no MSDN, mas não consigo encontrá-lo agora. Mas você pode olhar para a fonte de referência aqui .

Concluindo, você pode alterar com segurança a implementação do servidor, desde que não modifique a mensagem que a operação representa.

Em relação ao dimensionamento (deve ser uma questão diferente IMO)

  • Os valores padrão de limitação do WCF foram atualizados no .NET 4.5 para valores muito mais razoáveis ​​e agora dependem do processador (veja aqui ).
  • Não há mudanças em relação ao problema do pool de threads. O problema origina-se do tamanho inicial do conjunto de encadeamentos da porta de conclusão, que é inicialmente configurado para 4 vezes a quantidade dos processadores lógicos. Você pode usar ThreadPool.SetMinThreads para aumentar o valor por algum fator (veja este post ). Essa configuração também pode ser benéfica no lado do cliente.

Se você usar async no lado do servidor (ao chamar outros serviços, database, etc.), a situação de encadeamento poderá melhorar drasticamente porque você não estará desperdiçando encadeamentos de pool de encadeamentos que estão aguardando a conclusão do I / O.

A melhor coisa nessas situações é fazer um monte de benchmarking.