2012-10-11 100 views
11

He estado luchando durante unos días con un problema con nuestras aplicaciones de WPF y me pregunto si alguien se ha encontrado con esto antes y puede ayudarlo? El problema parece reducirse al cliente que genera un serializador "sobre la marcha" para manejar los tipos en esa llamada al método web. Cuando se llama a ese método por primera vez (el servicio web en sí mismo ya se está ejecutando), puede tomar, por ejemplo, 8 segundos, las llamadas siguientes pueden tomar, por ejemplo, 20ms. La CPU en el proceso WPF del cliente es v. Alta durante este retraso.Uso de WCF de WPF muy lento en el primer uso

Al usar XmlSerializer, hay una forma de pregenerar estos ensamblajes de serializador, usando svcutil. Cuando (como estamos) usando el WCF DataContractSerializer normal, esta opción no parece estar presente.

Lo que me gustaría es poder pregenerar este ensamblaje para todos los tipos en todos mis contratos de datos (mucho) o, como alternativa, reemplazar este proceso por uno personalizado que pueda codificar y pasar los datos en binario (poseemos ambos extremos de este servicio web/cliente y ambos son .NET 4). Ya he usado la compresión BinaryForamtter y GZip y, si bien esto acelera la transferencia de datos, siempre se restaura a XML para ser deserializado por el framework, de ahí que este problema persista.

¿Alguna idea?

Respuesta

8

Puede utilizar una biblioteca binaria como protobuf-net, que es bastante rápida, incluso si hay un costo de inicio inicial porque se debe generar código para cada tipo, todavía es way better than DataContractSerializer or BinaryFormatter. Deberías ganar unos segundos y tener una experiencia más uniforme. Puede ser easily integrated with WCF. Tenga en cuenta que WCF seguirá inspeccionando sus diversos contratos para generar el WSDL correcto y varios metadatos.

Hay otras cosas que pueden ralentizar el inicio de WCF, como la determinación del proxy web predeterminado. Asegúrese de que useDefaultWebProxy es false en su configuración de enlace si no tiene ningún uso para ello.

Aún así, encontrará que el arranque de WCF generalmente es lento sin importar lo que haga para optimizarlo. Personalmente, cansado de luchar contra la lentitud en un escenario similar (controlé ambos extremos, y el cliente era una aplicación de WPF), simplemente abandoné WCF y opté por ServiceStack + protobuf-net. La primera llamada pasó de 2-3 segundos a ~ 100 ms, y todas las llamadas HTTP posteriores son realmente instantáneas. La experiencia general del usuario ha mejorado mucho. Tenga en cuenta que de ninguna manera estoy afiliado a ServiceStack, esta es solo mi experiencia.

+0

Gracias Julien, ya tengo useDefaultWebProxy falso. He buscado usar protobuf-net, pero estoy teniendo problemas para entender si me requerirá volver a decorar todos mis tipos de datos con un nuevo atributo. Espero que no. En el sitio web dice que v2 se puede "usar sin atributos si se desea", pero todos los ejemplos usan atributos. ¿Esto mejorará la velocidad de inicio de la primera llamada, incluso en IIS (que es realmente obligatorio), es decir, es el serializador protobuf-net pregenerado en tiempo de compilación? –

+0

@SimonEvans, siempre y cuando tenga la propiedad 'Order' establecida en cada' DataMember', debería estar bien. Aunque no lo usé yo mismo (fui con protobuf desde el principio). –

+0

Julien, ¿quieres decir que tendría que agregar [ProtoMember (n)] a cada propiedad pública? Gracias por su ayuda –

0

Puede mejorar el tiempo de arranque en frío precargando su servicio WCF ... es decir. no espere a que la primera solicitud haga que se cargue ... cargue por adelantado.

sólo algunas ideas ... lo que "podría" ayudan a acelerar las cosas en la zona de la serialización.

En cuanto a la pregeneración de los ensamblajes de serialización para sus tipos de servicio ... existe la opción en Proyecto | Construir llamada "Generar ensamblaje de serialización" .... si se enciende "Encendido" entonces genera los ensamblajes en Tiempo de compilación en lugar de dinámicamente en tiempo de ejecución.

No está claro si esta opción es solo para la pregeneración de ensamblajes de serialización para serializadores basados ​​en XMLSerializer o también para DataContractSerializers.Podría intentar cambiarlo a "Encendido" para ver si marcó la diferencia.

También podría tratar de hacer esto desde el principio en el código en su cliente y servidor, para ejercitar los serializadores DataContract ... es decir. antes de que el cliente o el servidor tuviera que encargarse de una solicitud ... (no estoy seguro si ayudaría o no).

DataContractSerializer ps = new DataContractSerializer(typeof(Person)); 
DataContractSerializer cs = new DataContractSerializer(typeof(Company)); 
etc... 

para que sea más fácil de mantener que podría escribir una rutina que utiliza la reflexión para localizar los tipos que tiene la intención de serializar por ejemplo, busque los tipos marcados con DataContract .... o alguna otra heurística ... o una tabla predefinida.

+1

Gracias Colin, he intentado todo lo anterior y nada de esto hace la diferencia. El problema con la última sugerencia es que el problema con el que trato de lidiar es el lento arranque del cliente, por lo que realmente no importará si hago el inicio para los serializadores o si el marco lo hace, tomará el mismo tiempo. . La mayoría de las correcciones de inicio en frío se relacionan con el lado del servidor, lo cual no es un problema. La opción "Generar ensamblaje de serialización" solo funciona para XmlSerializer y solo si VS encuentra un proxy (tenemos el nuestro). –

+0

Este enlace puede brindarle algunas ideas de las diferentes estrategias que debe tomar .... http://www.icodeteam.net/default/post/iCodeTeam/35/Object-Serialization-in-NET-Available-serialization-libraries/ –

2

¿Confirmó al ver la referencia de servicio generada que DataContractSerializer está siendo utilizado? Es posible que, debido a una falta de coincidencia de esquemas durante la operación Agregar referencia de servicio, se haya generado el código XmlSerializer en lugar del DataContractSerializer predeterminado, que está causando este comportamiento típico de XmlSerializer. En este caso, como notó, puede pregenerar el código de serialización para mejorar el inicio en frío: http://msdn.microsoft.com/en-us/library/aa751883.aspx. Gracias.