que tiene un servidor de streaming que con un contrato de buscar algo como esto:Cómo detectar si WCF Streaming El cliente se desconecta de streaming medio
[ServiceContract]
public interface IStreamingService
{
[OperationContract(Action = "StreamingMessageRequest", ReplyAction = "StreamingMessageReply")]
Message GetStreamingData(Message query);
}
He aquí una aplicación rudimentaria con la materia (como la gestión de errores) eliminado para simplificar las cosas :
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[ErrorBehavior(typeof(StreamingServiceErrorHandler))]
public class StreamingService : IStreamingService
{
public StreamingService()
{
}
public Message GetStreamingData(Message query)
{
var dataQuery = query.GetBody<DataQuery>();
// Hook up events to let us know if the client disconnects so that we can stop the query...
EventHandler closeAction = (sender, ea) =>
{
dataQuery.Stop();
};
OperationContext.Current.Channel.Faulted += closeAction;
OperationContext.Current.Channel.Closed += closeAction;
Message streamingMessage = Message.CreateMessage(
MessageVersion.Soap12WSAddressing10,
"QueryMessageReply",
new StreamingBodyWriter(QueryMethod(dataQuery));
return streamingMessage;
}
public IEnumerable<object> QueryMethod (DataQuery query)
{
// Returns a potentially infinite stream of objects in response to the query
}
}
Esta aplicación utiliza un BodyWriter personalizada para transmitir los resultados de la QueryMethod:
public class StreamingBodyWriter : BodyWriter
{
public StreamingBodyWriter(IEnumerable items)
: base(false) // False should be passed here to avoid buffering the message
{
Items = items;
}
internal IEnumerable Items { get; private set; }
private void SerializeObject(XmlDictionaryWriter writer, object item)
{
// Serialize the object to the stream
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
foreach (object item in Items)
{
SerializeObject(writer, item);
}
}
}
El cliente se conecta y comienza a leer la secuencia de datos. Algo como esto:
public IEnumerable<T> GetStreamingData<T>(Message queryMessage)
{
Message reply = _Server.GetStreamingData(queryMessage);
// Get a chunckable reader for the streaming reply
XmlReader reader = reply.GetReaderAtBodyContents();
// Read the stream of objects, deserializing each one as appropriate
while (!reader.EOF)
{
object item = DeserializeObject(reader);
if (item == null)
continue;
// Yield each item as it's deserialized, resulting in a [potentially] never-ending stream of objects
yield return (T)item;
}
}
Esto funciona muy bien y recibo un flujo de objetos de vuelta al cliente. Muy agradable. El problema es cuando el cliente se desconecta a mitad de camino (ya sea con gracia o sin gracia). En cualquier caso, el servidor no se notificará de esta desconexión más que como un error recogido por el controlador de errores del servicio.
Como puede ver, he intentado conectar los eventos de canal cerrado y fallado en el método de servicio, pero no se activan cuando el cliente se desconecta.
Sospecho que estos eventos no se disparan porque con un contrato de transmisión por secuencias el servicio ya ha regresado desde el método de operación (GetStreamingData). Este método ha devuelto un mensaje con un cuerpo-escritor personalizado y es esta escritura corporal la que (más abajo en la pila del canal de servicio) está obteniendo los resultados del hilo de cálculo (a través de un IEnumerable) y transfiriéndolos al mensaje de respuesta. Dado que el método de operación ha regresado, supongo que estos eventos de canal no se disparan.
El enlace es una versión personalizada del enlace net.tcp (no dúplex) con solo dos elementos de enlace: BinaryMessageEncodingBindingElement y TcpTransportBindingElement. Sin seguridad ni nada. Básicamente solo net.tcp en bruto con mensajes binarios.
El problema es que cuando un cliente se desconecta, quiero que el servidor deje el hilo cálculo de fondo que está generando resultados y la alimentación de ellos en el IEnumerable siendo leído por el BodyWriter. El escritor del cuerpo se ha detenido (obviamente), pero el hilo continúa vivo.
Entonces, ¿dónde puedo conectar para descubrir si un cliente se ha desconectado a mitad de camino?
Actualización:
Hay dos casos principales de desconexión: desconexión explícita, ya sea debido a la disposición del cliente proxy o la terminación del proceso en el cliente; Desconexión pasiva, por lo general debido a una falla de la red (por ejemplo, ISP desconecta la conexión o el cable de red se desconecta).
En el primer caso, hay una excepción de conexión explícita que get recibe el servidor cuando intenta enviar datos nuevos en la secuencia. No hay problema.
El segundo escenario de una tubería de red rota es más problemático. Por lo general, esta condición se detecta en función del tiempo de espera de envío, pero dado que se trata de una interfaz de transmisión, el tiempo de espera de envío aumenta considerablemente (lo tengo configurado varios días ya que es concebible que las transferencias de datos de transmisión puedan durar tanto). Entonces, cuando un cliente se desconecta debido a un conducto de red escamosa, el servicio continúa enviando datos por una conexión que ya existe.
En este momento no sé de una buena manera de resolver la segunda opción. Sugerencias?
Me he encontrado con este problema y tengo casi la misma configuración que usted. Necesito saber cuándo el cliente se desconecta para poder disponer de los recursos escasos rápidamente. ¿Alguna vez pudo encontrar una solución o una solución para esto? Gracias. – Paccc