visual studio create crear consumir c# web-services wcf soap wsdl

c# - studio - WCF maximiza la CPU al esperar la función_TransparantProxyStub_CrossContext durante la llamada



wcf soap service c# (1)

Finalmente he resuelto este problema. La causa raíz parece ser el número de operaciones. Después de dividir el cliente generado de más de 900 operaciones a 12 cada una (siguiendo las instrucciones de esta pregunta ), pude reducir el tiempo de procesamiento del procesador en generar solicitudes casi a cero.

Este es el proceso final para optimizar el cliente de servicio generado desde el wsdl AXL de Cisco:

Genere código de cliente usando wsdl como tal:

svcutil AXLAPI.wsdl AXLEnums.xsd AXLSoap.xsd /t:code /l:C# /o:Client.cs /n:*,AxlNetClient

Procese el archivo de cliente generado para dividirlo en sub clientes:

Creé este script para procesar el código generado. Este script hace lo siguiente:

  1. Elimine los ServiceKnownType , FaultContract y XmlInclude .

Estos son útiles para el procesamiento xml, pero las clases generadas parecen ser incorrectas por lo que entiendo. El serviceknowntype, por ejemplo, es idéntico para todas las operaciones, aunque muchos de los know-types son únicos para cada operación. Esto reduce el tamaño total del archivo generado de 500 K + líneas a 250 K + con un aumento de rendimiento menor en el tiempo de creación de instancias del cliente.

  1. Separe los contratos de operación de la interfaz y los métodos de la base de clientes que implementan la interfaz.

  2. Cree subclientes, cada uno con 12 operaciones y su respectiva implementación.

Estos subclientes tienen tres partes principales. La primera parte es una clase parcial del cliente de la base de clientes original. Quiero que esta solución sea compatible con versiones anteriores, por lo que tengo métodos que hacen referencia al subcliente para que las llamadas al supercliente antiguo sigan funcionando llamando al nuevo subcliente. Un acceso de obtención estática iniciará el subcliente si se hace referencia a cualquiera de sus operaciones implementadas. También se agregan eventos para cuando se llama close o abort para que los subclientes puedan seguir ejecutando estas operaciones.

La segunda y tercera parte del subcliente es la interfaz y la clase subcliente que implementa las 12 operaciones.

Luego eliminé la interfaz y los métodos del cliente del cliente original generado. Remplacé los constructores de cliente para el cliente original simplemente para almacenar los datos de enlace y punto final para que los subclientes los usen cuando sea necesario. Las llamadas de cierre y anulación se recrearon como invocadores de eventos a los que cada subcliente se suscribiría cuando se crearan instancias.

Por último, he movido la autenticación a un comportamiento de punto final personalizado similar a lo que se describe aquí . El uso de IClientMessageInspector para enviar el encabezado de autenticación se guarda de inmediato en una llamada de ida y vuelta al servidor donde WCF desea enviar una solicitud anónima antes de la autenticación. Esto me da aproximadamente 2 segundos de incremento dependiendo del servidor.

En general, tengo un aumento en el rendimiento de 70 segundos a 2.5 segundos.

Obtengo un uso intensivo de la CPU cuando hago llamadas a la API AXL SOAP de Cisco usando WCF. Empiezo creando una base de clientes de modelo de servicio usando clases generadas de wsdl. Estoy usando basichttpbinding y transfermode como buffer. Al ejecutar una llamada, la CPU alcanza su máximo, y un perfil de CPU muestra que el 96% del tiempo de CPU está en _TransparentProxyStub_CrossContext@0 desde clr.dll que se llama después de llamadas como base.Channel.getPhone(request); . Más correctamente, la llamada maximiza el núcleo de CPU en el que se está ejecutando el proceso.

Aquí hay un recorte de la creación del cliente de wsdl generate

[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] public partial class AXLPortClient : System.ServiceModel.ClientBase<AxlNetClient.AXLPort>, AxlNetClient.AXLPort { public AXLPortClient() { } public AXLPortClient(string endpointConfigurationName) : base(endpointConfigurationName) { } ...

Así es como creo el cliente:

public class AxlClientFactory : IAxlClientFactory { private const string AxlEndpointUrlFormat = "https://{0}:8443/axl/"; public AXLPortClient CreateClient(IUcClientSettings settings) { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; ServicePointManager.Expect100Continue = false; var basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport); basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; basicHttpBinding.MaxReceivedMessageSize = 20000000; basicHttpBinding.MaxBufferSize = 20000000; basicHttpBinding.MaxBufferPoolSize = 20000000; basicHttpBinding.ReaderQuotas.MaxDepth = 32; basicHttpBinding.ReaderQuotas.MaxArrayLength = 20000000; basicHttpBinding.ReaderQuotas.MaxStringContentLength = 20000000; basicHttpBinding.TransferMode = TransferMode.Buffered; //basicHttpBinding.UseDefaultWebProxy = false; var axlEndpointUrl = string.Format(AxlEndpointUrlFormat, settings.Server); var endpointAddress = new EndpointAddress(axlEndpointUrl); var axlClient = new AXLPortClient(basicHttpBinding, endpointAddress); axlClient.ClientCredentials.UserName.UserName = settings.User; axlClient.ClientCredentials.UserName.Password = settings.Password; return axlClient; } }

El código wsdl generado para la API AXL es muy grande. Tanto las llamadas iniciales como posteriores tienen el problema de CPU, aunque las llamadas posteriores son más rápidas. ¿Hay algo más que pueda hacer para solucionar este problema? ¿Hay alguna manera de reducir este alto uso de la CPU?

Actualizar

Un poco más de información con la recompensa:

Creé las clases de C # así:

svcutil AXLAPI.wsdl AXLEnums.xsd AXLSoap.xsd /t:code /l:C# /o:Client.cs /n:*,AxlNetClient

Debe descargar el wsdl para la API AXL de Cisco desde un sistema de administrador de llamadas. Estoy usando la versión 10.5 de la API. Creo que la mayor desaceleración está relacionada con el procesamiento de XML. ¡El WSDL para la API es enorme y las clases resultantes forman 538406 líneas de código!

Actualización 2

He activado el seguimiento WCF con todos los niveles. La diferencia de tiempo más grande se encuentra en la actividad de acción de proceso entre "Se escribió un mensaje" y "Se envió un mensaje por un canal" en el que pasa casi un minuto completo entre estas dos acciones. Otras actividades (construir canal, abrir base de clientes y cerrar base de clientes) se ejecutan relativamente rápido.

Actualización 3

Hice dos cambios en las clases de clientes generadas. Primero, ServiceKnownTypeAttribute de todos los contratos de operación. En segundo lugar, eliminé el XmlIncludeAtribute de algunas de las clases serializables. Estos dos cambios redujeron el tamaño del archivo del cliente generado en más del 50% y tuvieron un pequeño impacto en los tiempos de prueba (una reducción de aproximadamente 10s en un resultado de prueba de los 70).

También noté que tengo aproximadamente 900 contratos de operación para una única interfaz de servicio y punto final. Esto se debe a wsdl para la API AXL agrupando todas las operaciones bajo un solo espacio de nombres. Estoy pensando en romper esto, pero eso significaría crear múltiples bases de clientes que implementarían cada una una interfaz reducida y terminarían rompiendo todo lo que implementa esta biblioteca wcf.

Actualización 4

Parece que el número de operaciones es el problema central. Pude separar las operaciones y las definiciones de interfaz por verbo (por ejemplo, obtiene, agrega, etc.) en su propia base de clientes e interfaz (un proceso muy lento que utiliza texto sublime y expresiones regulares como resharper y codemaid no podía manejar el archivo grande que aún es 250K + líneas). Una prueba del cliente "Obtener" con alrededor de 150 operaciones definidas resultó en una ejecución de 10 segundos para getPhone en comparación con un resultado anterior de 60 segundos. Esto todavía es mucho más lento de lo que debería ser, simplemente como crear esta operación en resultados de violín en una ejecución de 2 segundos. La solución probablemente reducirá aún más el conteo de operaciones al tratar de separar más las operaciones. Sin embargo, esto agrega un nuevo problema de romper todos los sistemas que utilizan esta biblioteca como un único cliente.