Estoy usando un netNamedPipeBinding
para realizar la comunicación entre procesos de WCF desde una aplicación de Windows a un servicio de Windows.excepción WCF recibida al cerrar la conexión con devoluciones de llamada en uso
Ahora mi aplicación funciona bien en todas las demás cuentas (después de luchar contra mi parte justa de las excepciones WCF como cualquiera que haya trabajado con WCF lo sabría ...) pero este error es bastante resistente.
Para pintar una imagen de mi escenario: mi servicio de Windows podría ponerse en cola para hacer algún trabajo en un momento dado presionando un botón en la aplicación de Windows y luego hablar sobre el netNamedPipeBinding
que es un enlace que admite devoluciones de llamada (dos comunicación directa) si no está familiarizado e inicia una solicitud para realizar este trabajo (en este caso, un procedimiento de carga de archivos) también lanza las devoluciones de llamada (eventos) cada pocos segundos, desde el progreso del archivo hasta la velocidad de transferencia, etc. a la aplicación de Windows, por lo que hay una integración bastante estrecha entre el cliente y el servidor; así es como recibo mi progreso de lo que se está ejecutando en mi servicio de Windows en mi aplicación de Windows.
Ahora, todo está bien, los dioses WCF están relativamente contentos conmigo en este momento, aparte de una desagradable excepción que recibo cada vez que apago la aplicación prematuramente (lo cual es un escenario perfectamente válido). Mientras que una transferencia está en curso, y las devoluciones de llamada están disparando bastante fuerte, recibo este error:
System.ServiceModel.ProtocolException:
The channel received an unexpected input message with Action
'http://tempuri.org/ITransferServiceContract/TransferSpeedChangedCallback'
while closing. You should only close your channel when you are not expecting
any more input messages.
Ahora entiendo que el error, pero por desgracia no puedo garantizar que cerrar mi canal después de no recibir ningún messsages más de entrada, como se el usuario puede cerrar la aplicación en cualquier momento, por lo tanto, el trabajo continuará en el fondo del servicio de Windows (algo así como el funcionamiento de un escáner de virus). El usuario debe poder iniciar y cerrar la aplicación de herramientas de administración de ganancias tanto como lo desee sin interferencia.
Ahora el error, recibo inmediatamente después de realizar mi llamada Unsubscribe()
que es la segunda última llamada antes de terminar la aplicación y lo que creo que es la forma preferida de desconectar un cliente WCF. Todo lo que cancela la suscripción antes de cerrar la conexión es simplemente eliminar la identificación del cliente de una matriz que se almacenó localmente en el servicio win service wcf (ya que esta es una instancia COMPARTIDA tanto por el servicio ganador como por la aplicación Windows; eventos programados por sí mismo) y después de la eliminación de la matriz de identificador de cliente que realizo, lo que espero (siento) debe ser una desconexión limpia.
El resultado de esto, además de recibir una excepción, es que mi aplicación se cuelga, la UI está en bloqueo total, barras de progreso y todo a mitad de camino, con todas las señales apuntando a tener una condición de carrera o punto muerto WCF [suspiro], pero ahora soy bastante experto en hilos y creo que esta es una situación relativamente aislada y leyendo la excepción tal como está, no creo que sea un tema 'hilo' per se, ya que establece más un problema de desconexión temprana que luego hace girar todos mis hilos en el caos, quizás causando el bloqueo.
Mi enfoque Unsubscribe()
en el clientese parece a esto:
public void Unsubscribe()
{
try
{
// Close existing connections
if (channel != null &&
channel.State == CommunicationState.Opened)
{
proxy.Unsubscribe();
}
}
catch (Exception)
{
// This is where we receive the 'System.ServiceModel.ProtocolException'.
}
finally
{
Dispose();
}
}
Y mi método Dispose()
, que debe realizar la desconexión limpia:
public void Dispose()
{
// Dispose object
if (channel != null)
{
try
{
// Close existing connections
Close();
// Attempt dispose object
((IDisposable)channel).Dispose();
}
catch (CommunicationException)
{
channel.Abort();
}
catch (TimeoutException)
{
channel.Abort();
}
catch (Exception)
{
channel.Abort();
throw;
}
}
}
Y la contraparte servicio WCF Subscription()
y la clase atributos (para referencia) en el servicio de Windows servidor (nada complicado aquí y se produce mi excepción lado del cliente):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferService : LoggableBase, ITransferServiceContract
{
public void Unsubscribe()
{
if (clients.ContainsKey(clientName))
{
lock (syncObj)
{
clients.Remove(clientName);
}
}
#if DEBUG
Console.WriteLine(" + {0} disconnected.", clientName);
#endif
}
...
}
Interfaz de:
[ServiceContract(
CallbackContract = typeof(ITransferServiceCallbackContract),
SessionMode = SessionMode.Required)]
public interface ITransferServiceContract
{
[OperationContract(IsInitiating = true)]
bool Subscribe();
[OperationContract(IsOneWay = true)]
void Unsubscribe();
...
}
Interfaz del contrato de devolución de llamada, que no hace nada muy emocionante, sólo llama a eventos a través de los delegados, etc. La razón por la que esto es incluido para mostrar usted mis atributos Hice aliviar una serie de callejones sin salida ya mediante la inclusión de UseSynchronizationContext = false
:
[CallbackBehavior(UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferServiceCallback : ITransferServiceCallbackContract
{ ... }
Realmente espero que alguien me puede ayudar! Muchas gracias = :)
no sé sobre el tema específico, pero para información suena * * posiblemente debido a la forma en WCF utiliza sincronización de contexto (que es el medio de la forma en winforms etc) el bodrio de roscado. –
Gracias Marc, sí, eso me sorprendió y alivié una serie de bloqueos al leer sobre ese tema, el truco fue establecer 'UseSynchronizationContext = false' en el contrato de devolución de llamada;) Añadiré esto a mis ejemplos. – GONeale
ah, a la derecha; bueno verte ya lo tenía cubierto; p –