.net silverlight wcf silverlight-4.0 wcf-proxy

.net - Silverlight 4.0 y proxy de cliente WCF: cómo crear y cómo cerrar instancias



silverlight-4.0 wcf-proxy (2)

La creación de proxy no es costosa en relación con el viaje de ida y vuelta de la llamada. He visto comentarios que dicen llamar a CloseAsync inmediatamente después de tus llamadas a otros métodos asíncronos, pero parece ser defectuoso. En teoría, el cierre pasa a un estado pendiente y ocurre después de que finalicen sus otras llamadas asíncronas. En la práctica, he visto que las llamadas terminan sorprendentemente rápido con un fallo, y luego el mismo CloseAsync falla porque el canal ya ha fallado.

Lo que hice fue crear una clase Caller<TResult> que tiene una cantidad de sobrecargas de método genérico CallAsync que aceptan argumentos y una devolución de llamada de tipo Action<TResult> . Debajo de las portadas, la persona que XxxCompleted evento XxxCompleted y verificará si el motivo de la finalización se debió a un error o no. Si es un error, Abort el canal. Si no hay error, llamaría a CloseAsync y luego invocaría la devolución de llamada. Esto evita errores "tontos", como tratar de usar el canal en estado de falla.

Todo lo anterior supone un modelo create-proxy-make-call-discard-use-of-proxy. Si tuvo que hacer muchas llamadas en sucesión rápida, podría adaptar este enfoque para contar el número de llamadas en vuelo, y al finalizar el último, cierre o aborte.

Es probable que sea raro que la sobrecarga de creación de proxy en una llamada o por conjunto de llamadas relacionadas sea un problema. Solo si la sobrecarga es demasiado alta, ¿buscaría una estrategia de caché o reutilización de proxy? Recuerde, cuanto más tiempo tenga un recurso, mayor es la probabilidad de fracaso. En mi experiencia al menos, cuanto menor es el tiempo de vida, mejor es el rendimiento percibido por el usuario, porque lo interrumpes menos, no es necesario mantener la lógica de reintento (o al menos menos) para mantenerlo, y tú " Confíe más en que no está perdiendo memoria o recursos al saber con precisión cuándo deshacerse de ellos.

Con respecto a su pregunta sobre ejemplos que no se cierran ... bueno, esos son ejemplos, y generalmente son unidimensionales e incompletos porque ilustran un uso general, no todos los detalles sobre lo que debe hacer a lo largo de toda la vida de una aplicación.

El tema del ciclo de vida del proxy del servicio WCF de Silverlight no es muy claro para mí. He leído varios materiales, recursos, respuestas aquí, pero aún no entiendo completamente la supuesta mejor manera de usarlos.

Estoy usando un enlace binario personalizado en Silverlight 4.0 actualmente.

¿La creación de un proxy en Silverlight es una operación costosa? ¿Deberíamos tratar de compartir una instancia de proxy en el código o crear una nueva mejor? ¿Deberíamos bloquear si compartimos en caso de que varios hilos accedan a él?

Como un error en un proxy daña el estado de un proxy, creo que compartir un proxy no es una buena idea, pero he leído que la creación es cara, por lo que no está 100% claro qué hacer aquí.

Y con cierre: los clientes del servicio WCF silverlight solo proporcionan el método CloseAsync. Además, los proxies requieren que se use cierta lógica cuando están cerrados (si tienen una falla, debemos llamar a Abort () que es sincrónico en Silverlight y si no, deberíamos cerrar la sincronización que no es síncrona o ¿qué?).

En muchas muestras oficiales de Silverlight, los proxies de MS no están cerrados en absoluto, ¿es solo un defecto de materiales o un enfoque esperado para ellos?

El tema es muy importante para mí y quiero una comprensión clara de todas las cosas que se deben considerar que actualmente no tengo.

(Vi que esta pregunta ¿Cuál es el ciclo de vida adecuado de un proxy de cliente de servicio WCF en Silverlight 3? Parece cercana a la mía pero no puedo decir que estoy satisfecho con la calidad de las respuestas)

Realmente me gustaría ver un código de muestra que use, cree, cierre, etc. Proxies WCF y, lo que es más importante, explique por qué es la mejor manera posible. También creo (actualmente creo) que debido a la naturaleza del problema, debería haber un solo enfoque de buenas prácticas / patrón de uso general para usar (crear, reutilizar, cerrar) proxies de WCF en Silverlight.


Resumen : creo que la mejor práctica es instanciar el cliente de su servicio web cuando esté a punto de usarlo, luego déjelo fuera del alcance y obtenga la recolección de basura. Esto se refleja en las muestras que ve venir de Microsoft. La justificación sigue ...

Completo : la mejor descripción completa del proceso que he encontrado se encuentra en Cómo acceder a un servicio de Silverlight . Aquí el ejemplo muestra el patrón típico de crear instancias del cliente del servicio web y permitir que salga del alcance (sin necesidad de cerrarlo). Los clientes del servicio web heredan de ClientBase que tiene un método Finalize que debería liberar los recursos no administrados si es necesario cuando el objeto es basura.

Tengo una cantidad decente de experiencia en el uso de servicios web, y utilizo proxies e instancias justo antes de usarlos, luego les permito recolectar basura. Nunca he tenido un problema con este enfoque. Leí en blogs.msdn.com/b/wenlong/archive/2007/10/27/… que decía que la creación del proxy era costosa, pero incluso él dice que el rendimiento ha mejorado en .NET 3.5 (¿quizás ha vuelto a mejorar desde entonces?). Lo que sí puedo decir es que el rendimiento es un término relativo y, a menos que los datos que se recuperen no sean de tamaño trivial, se dedicará mucho más tiempo a serializar / deserializar y transportar que a crear la conexión. Esta ha sido ciertamente mi experiencia, y es mejor optimizar primero en esas áreas.

Por último, dado que creo que mis opiniones hasta ahora pueden ser insuficientes, escribí una prueba rápida. Creé un servicio web habilitado para Silverlight usando la plantilla provista con Visual Web Developer 2010 Express (con un método de vacío predeterminado llamado DoWork() ). Luego, en mi cliente Silverlight de muestra, lo llamé usando el siguiente código:

int counter=0; public void Test() { ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); client.DoWorkCompleted += (obj, args) => { counter++; if (counter > 9999) { for(int j=0;j<10;j++) GC.Collect(); System.Windows.MessageBox.Show("Completed"); } }; client.DoWorkAsync(); }

Luego llamé al método Test usando for(int i=0;i<10000;i++) Test(); y encendió la aplicación. Tomó un poco más de 20 segundos cargar la aplicación y completar las llamadas al servicio web (todas las 10,000). A medida que se realizaban las llamadas al servicio web, vi que el uso de la memoria para el proceso aumentaba a más de 150 MB, pero una vez que se completaban las llamadas y se GC.Collect() el uso de la memoria GC.Collect() a menos de la mitad. Lejos de ser una prueba perfecta, parece confirmarme que no se escapó memoria, o que era insignificante (considerando que probablemente no sea común llamar a 10,000 llamadas de servicio web usando instancias de cliente separadas). También es un modelo mucho más simple que mantener un objeto proxy y tener que preocuparse por fallas y tener que volver a abrirlo.

Justificación de la metodología de prueba: Mi prueba se centró en 2 problemas potenciales. Una es una pérdida de memoria, y la otra es el tiempo de procesamiento del procesador creando y destruyendo los objetos. Mi recomendación es que sea seguro seguir los ejemplos proporcionados por la empresa (Microsoft) que suministra las clases. Si le preocupa la eficacia de la red, entonces no debería tener problemas con mi ejemplo, ya que la creación / eliminación adecuada de estos objetos no afectaría la latencia de la red. Si el 99% del tiempo dedicado es tiempo de red, entonces optimizar para una mejora teórica en el 1% probablemente sea un desperdicio en términos de tiempo de desarrollo (suponiendo que haya incluso un beneficio que ganar, que creo que mi prueba muestra claramente que hay poco / ninguna). Sí, las llamadas de red fueron locales, lo que quiere decir que en el transcurso de 10.000 llamadas de servicio, solo se gastarán unos 20 segundos en esperar a los objetos. Eso representa ~ 2 milisegundos por llamada de servicio gastada en la creación de los objetos. En cuanto a la necesidad de llamar a Dispose, no quise dar a entender que no deberías llamarlo, simplemente que no parecía necesario. Si olvida (o simplemente elige no hacerlo), mis pruebas me llevaron a creer que Dispose se llamaba en Finalize para estos objetos. Aun así, probablemente sería más eficiente llamar a ti mismo, pero aún así el efecto es insignificante. Para la mayoría de los desarrollos de software, obtienes más ganancias al inventar algoritmos y estructuras de datos más eficientes que por cuestiones como estas (a menos que haya una fuga de memoria grave). Si necesita más eficiencia, quizás no deba utilizar servicios web, ya que existen opciones de tránsito de datos más eficientes que un sistema basado en XML.