Diferentes formas de la interfaz de contrato de servicio WCF

Parece que puedo cambiar libremente entre las siguientes tres versiones diferentes de la misma API de interfaz de contrato de WCF, sin romper los 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); } 

La aplicación cliente de prueba existente sigue funcionando sin ningún tipo de recomstackción o toque. Si recompilo el servicio y vuelvo a importar su referencia en la aplicación cliente, la definición WSDL sigue siendo la misma , 1: 1.

Mis preguntas:

  • ¿Es un comportamiento legítimo en el que puedo confiar? Está documentado en cualquier lugar?

La idea es convertir un conjunto de métodos sincrónicos del estilo SomeMethod en métodos TAP SomeMethodAsync , para usar async/await en su implementación y así mejorar la escalabilidad del servicio WCF, sin romper los clientes existentes.

Además, ha habido problemas conocidos con el escalado del servicio WCF en .NET 3.5 y .NET 4.0. Están documentados en el artículo de MSKB “El servicio WCF puede ampliarse lentamente bajo carga” y el artículo de CodeProject ” Ajuste de WCF para crear API REST asíncrona altamente escalable” . Básicamente, no fue suficiente implementar las API de contrato de servicio como naturalmente asíncronas, el tiempo de ejecución de WCF aún estaba bloqueando el hilo de solicitud.

  • ¿Alguien sabe si este problema se ha solucionado para .NET 4.5.x , out-of-the-box? O los ajustes adicionales todavía se requieren?

Las operaciones de WCF pueden definirse usando sincrónicamente, EAP o (a partir de .NET 4.5) TAP. Desde MSDN :

Los clientes pueden ofrecer al desarrollador cualquier modelo de progtwigción que elijan, siempre que se observe el patrón de intercambio de mensajes subyacente. Entonces, también pueden los servicios implementar operaciones de cualquier manera, siempre que se observe el patrón de mensaje especificado.

En realidad, puede tener los 3 patrones en una sola interfaz de contrato, y todos se relacionan con el mismo mensaje.

En el cable, no hay diferencia en cómo se ejecutan las operaciones. WSDL (que WCF crea a partir de ABC de cada punto final – dirección, enlace y contrato) no contiene esta información. Se genera a partir de descripciones de operación .

Si observa la clase OperationDescription , que se utiliza en un ContractDescription , verá que cada operación tiene estas propiedades: SyncMethod , BeginMethod , EndMethod y TaskMethod . Al crear una descripción, WCF combinará todos los métodos de acuerdo con el nombre de la operación en una sola operación. Si hay alguna falta de coincidencia entre las operaciones con el mismo nombre en diferentes patrones (por ejemplo, diferentes parámetros) WCF arrojaría una excepción que detalla exactamente lo que está mal. WCF asume automáticamente (opcional) el sufijo “Async” para los métodos basados ​​en tareas, y el prefijo Begin / End para APM.

El lado del cliente y del servidor no tienen ninguna relación en este sentido. La utilidad que genera las clases proxy de WSDL ( svcutil ), puede construir proxies para cualquier patrón de ejecución. Ni siquiera tiene que ser un servicio WCF.

En el lado del servidor, si se implementa más de un patrón, WCF usará solo uno en el siguiente orden de precedencia: Tarea, Sincronización y APM. Esto está documentado en algún lugar de MSDN, simplemente no puedo encontrarlo ahora. Pero puedes mirar la fuente de referencia aquí .

En conclusión, puede cambiar de forma segura la implementación de su servidor siempre que no modifique el mensaje que representa la operación.

En cuanto a la escala (debería ser una pregunta diferente OMI)

  • Los valores predeterminados de regulación de WCF se han actualizado en .NET 4.5 a valores mucho más razonables y ahora dependen del procesador (ver aquí ).
  • No hay cambios en cuanto al problema de la agrupación de hilos. El problema radica en el tamaño inicial del grupo de subprocesos del puerto de finalización, que inicialmente se establece en 4 veces la cantidad de los procesadores lógicos. Puede usar ThreadPool.SetMinThreads para boost la cantidad por algún factor (consulte esta publicación ). Esta configuración también podría ser beneficiosa para el lado del cliente.

Si usa asincronización en el lado del servidor (cuando llama a otros servicios, base de datos, etc.), la situación del subprocesamiento podría mejorar dramáticamente porque no desperdiciará los subprocesos del grupo de subprocesos que solo están esperando a que IO lo complete.

Lo mejor en estas situaciones es hacer MUCHO benchmarking.