2012-07-29 12 views
17

Este es un problema que he estado investigando en la última semana y no puedo encontrar ninguna solución. Publicaciones encontradas pidiendo lo mismo pero nunca obteniendo una respuesta, con suerte esto ayudará a otros también.¿Cómo abortar una secuencia del servicio WCF sin leerla hasta el final?

Tengo un servicio WCF que devuelve un objeto que contiene un stream dentro de él. Uso basicHttpBinding con transferencia de transmisión y Mtom para enviarlo al cliente.

El cliente llama al servicio WCF y cierra el proxy inmediatamente después de recibir el objeto de respuesta.

A continuación, el cliente lee la secuencia que obtuvo del servicio WCF y la escribe en un archivo en el disco local. Todo esto funciona bien.

Mi problema es cuando el cliente quiere abortar la operación y dejar de descargar los datos del servicio WCF. Si llamo al .close() en la transmisión, por ejemplo: serverReply.DataStream.Close();, entonces bloquea y lee todo el flujo del servicio WCF hasta su finalización antes de continuar. La transmisión puede ser bastante grande y la red no siempre es rápida.

Esto es muy indeseable para el uso de ambos recursos de red, que básicamente se desperdicia en datos que ya no tienen uso. Y dado que basicHttpBinding permite solo dos conexiones TCP simultáneas (de manera predeterminada) al servidor de servicio WCF, bloquea otros intentos de conexión hasta que la transmisión se lee hasta el final.

Podría aumentar el número de conexiones simultáneas, pero sería una mala solución, ya que crearía una abertura para problemas.

Por ejemplo, 20 descargas abortadas que aún están descargando los datos para descartarlos. Necesito hacer que la transferencia se detenga por completo.

En el cliente, el objeto de secuencia es solo una clase normal Stream, por lo que solo tiene el método de cierre, nada más.

Llamar a .close() o .abort() en el objeto proxy no ayuda, tampoco lo destruye usando .dispose() o cualquier otro método. En el lado del servidor, manejo el evento OperationContext.OperationCompleted, pero no se activa hasta que los datos del stream se leen hasta el final.

Entonces la pregunta es, ¿cómo cierro/aborto la secuencia sin leerla por completo?

+0

¿Alguna suerte con esto? – Schultz9999

+0

Sufriendo el mismo problema al enviar archivos realmente grandes ... parece que debe faltar algo realmente obvio. probablemente tenga que implementar fragmentación como una solución alternativa. –

Respuesta

0

¿Ha intentado jugar con binding.MaxBufferSize?
¿Ha intentado jugar con la configuración de archivo App.config por ejemplo:

<bindings> 
    <wsHttpBinding> 
    <binding name="default" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" 
      closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" > 
     <readerQuotas maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" 
        maxDepth="64" maxStringContentLength="2147483647" /> 
    </binding> 

    </wsHttpBinding> 
</bindings> 

que reduzca al mínimo los tiempos de espera anf longitudes de amortiguamiento y tratar de abortar o cerca y ver qué pasa.

+1

Lo intenté, pero no ayuda. Una vez que el servidor comienza a enviar la transmisión, no se detiene hasta que el cliente la recibe. Cerrar el proxy no hace nada. Parece que no hay una forma evidente de detener la comunicación. Cuando el cliente deja de leer la transmisión, puedo ver que la ventana cero de tcp vuelve al servidor. Y el servidor envía periódicamente una sonda de cero de ventana para ver si el cliente está listo para leer nuevamente. Y, por supuesto, el cliente vuelve a enviar la ventana cero. Esto continúa para siempre hasta que se mate el proceso. – Yev

+0

¿Ha intentado leer la transmisión usando solo HttpClient Class y viendo si puede cerrar la transmisión? –

+0

¿Cómo hago eso sin llamar a un servicio de WCF? He investigado un poco más y parece que no hay forma de cerrar la transmisión desde el lado del cliente. Probé con un enfoque diferente. Creé otro servicio, un servicio de control e intenté cerrar la transmisión desde allí (en el lado del servidor). Pero sin suerte. Algo simplemente no funciona, no cierra ni desecha. – Yev

1

Después de la investigación, encontré que el cliente de WCF seguirá leyendo desde la transmisión hasta que closeTimeout haya finalizado, y luego abortará la conexión. Puede disminuir closeTimeout en el cliente para minimizar el problema.

NOTA: Debe envolver el código que dispone una secuencia en el bloque try/catch. El método stream.Dispose() arrojará TimeoutException que frena una directriz de not throwing exceptions in Dispose method.

0

Creo que simplemente está recibiendo el búfer después de cerca. Debe establecer maxBufferSize a un valor inferior.

Es posible que también desee restringir la cantidad de datos leídos en el servidor al envolver la secuencia y anular la lectura. Use trozos más pequeños si tiene un cliente de ancho de banda bajo y devuelva un recuento correspondiente del método de lectura para que coincida con la cantidad que realmente lee. Esto restringiría la tasa de llenado del buffer.

Mis propias pruebas sobre este tema me implicó escribir un NeverEndingStream y devolver datos siempre. En algún momento llamé cerca del cliente y casi inmediatamente se llamó al cierre en el servidor. Esto sugiere que el búfer simplemente se vació porque claramente nunca podría leer mi flujo hasta el final.

Si aún tiene problemas, le sugiero que realice un seguimiento de la sincronización del método Read en la transmisión reemplazada. Si currentReadtime - the lastReadTime is> x entonces, en su lugar, puede llamar a Close y lanzar una excepción. Eso lo matará con seguridad.

Cuestiones relacionadas