¿Cuál es la mejor solución para el problema de bloqueo del cliente WCF `using`?
Frecuentes
Visto 110,377 equipos
412
Me gusta crear instancias de mis clientes de servicio WCF dentro de un using
block, ya que es prácticamente la forma estándar de usar recursos que implementan IDisposable
:
using (var client = new SomeWCFServiceClient())
{
//Do something with the client
}
Pero, como se indica en este artículo de MSDN, envolviendo un cliente WCF en un using
El bloque podría enmascarar cualquier error que provoque que el cliente quede en un estado de falla (como un tiempo de espera o un problema de comunicación). En pocas palabras, cuando Dispose()
se llama, el cliente Close()
El método se activa, pero arroja un error porque está en un estado defectuoso. La excepción original queda enmascarada por la segunda excepción. No está bien.
La solución alternativa sugerida en el artículo de MSDN es evitar por completo el uso de using
bloquear y, en su lugar, crear una instancia de sus clientes y usarlos de esta manera:
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
En comparación con el using
bloque, creo que eso es feo. Y mucho código para escribir cada vez que necesite un cliente.
Afortunadamente, encontré algunas otras soluciones, como esta en el blog (ahora desaparecido) IServiceOriented. Empiece con:
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
Que luego permite:
Service<IOrderService>.Use(orderService =>
{
orderService.PlaceOrder(request);
});
Eso no está mal, pero no creo que sea tan expresivo y fácilmente comprensible como el using
bloquear.
La solución que estoy tratando de usar actualmente, la primera vez que leí en blog.davidbarret.net. Básicamente, anula la del cliente Dispose()
método donde sea que lo use. Algo como:
public partial class SomeWCFServiceClient : IDisposable
{
void IDisposable.Dispose()
{
if (this.State == CommunicationState.Faulted)
{
this.Abort();
}
else
{
this.Close();
}
}
}
Esto parece ser capaz de permitir using
bloquear de nuevo sin el peligro de enmascarar una excepción de estado defectuoso.
Entonces, ¿hay otras trampas que deba tener en cuenta para usar estas soluciones? ¿A alguien se le ha ocurrido algo mejor?
0 Respuestas
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c# vb.net wcf using wcf-client or haz tu propia pregunta.
El último (que inspecciona this.State) es una carrera; es posible que no tenga fallas cuando verifique el booleano, pero podría tener fallas cuando llame a Close (). - Brian
Lees estado; no tiene fallas. Antes de llamar a Close (), el canal falla. Lanzamientos cercanos (). Juego terminado. - Brian
El tiempo pasa. Puede ser un período de tiempo muy corto, pero técnicamente, en el período de tiempo entre la verificación del estado del canal y la solicitud de cierre, el estado del canal puede cambiar. - Eric King
Yo usaría
Action<T>
en lugar deUseServiceDelegate<T>
. menor. - hIpPyRealmente no me gusta este ayudante estático
Service<T>
ya que complica las pruebas unitarias (como hacen la mayoría de las cosas estáticas). Preferiría que no sea estático para que pueda inyectarse en la clase que lo está usando. - Fabio Marreco