.net wcf performance

.net - ¿Renovar un cliente WCF cuando SCT ha expirado?



performance (4)

Puede resolver sus problemas mediante el uso de delegados. Esto permitirá invocar de forma segura la acción y, si falla, detectar la excepción, construir una nueva instancia de servicio y realizar la acción nuevamente.

using System; using System.ServiceModel; using System.ServiceModel.Security; public static class Service { private static IService _service; public static void Invoke(Action<IService> action) { try { action(_service); } catch (MessageSecurityException) { if (_service.State != CommunicationState.Faulted) { throw; } _service.Abort(); _service = CreateFreshInstance(); action(_service); } } }

A continuación, puede llamar a su clase de ayuda como Service.Invoke(s => s.Method()); invocar el IService.Method ().

Estoy usando WCF para un punto final de soap utilizando el modo de seguridad "TransportWithMessageCredential".

El cliente / servidor de WCF usa SCT (Token de contexto de seguridad) para mantener una conexión segura, y está funcionando según lo previsto en el caso general.

Sin embargo, después de un período de inactividad, la SCT expirará y la próxima llamada al método causará una MessageSecurityException:

Se recibió un error no asegurado o incorrectamente seguro de la otra parte. Vea la FaultException interna para el código de falla y detalles

Excepción interna:

El mensaje no pudo ser procesado. Esto es más probable porque la acción '' http://tempuri.org/IMyService/MyMethod '' es incorrecta o porque el mensaje contiene un token de contexto de seguridad no válido o caducado o porque hay una falta de coincidencia entre los enlaces. El token de contexto de seguridad no sería válido si el servicio abortó el canal debido a inactividad. Para evitar que el servicio interrumpa prematuramente las sesiones inactivas, aumente el tiempo de espera de recepción en el enlace del punto final del servicio.

En llamadas posteriores, renuevo la conexión cuando veo que CommunicationState tiene una falla. Pero no puedo encontrar una forma de comprobar de forma preventiva si la SCT ha expirado antes de realizar mi llamada de método.


Es posible que pueda usar el patrón decorater para manejar excepciones con los proxies WCF. Si esta ruta está abierta para usted, puede considerar algo como esta configuración que manejará la falla del proxy y la reinicializará para los llamantes. Las siguientes excepciones serán lanzadas a la persona que llama.

//Proxy implements this interface IMyService { void MyMethod(); } //Decorator 1 public class MyServiceProxyRetryingDecorator : IMyService { //This is the real proxy that might be faulted private realProxy = new RealProxy(); public void MyMethod() { ReEstablishProxyIfNecessary(); //now just pass the call to the proxy, if it errors again, //do more handling or let the exception bubble up realProxy.MyMethod(); } private void ReEstablishProxyIfNecessary() { if(realProxy.CommunicationState == CommunicationState.Faulted) { realProxy.Abort(); realProxy = new RealProxy(); } } }

Una versión diferente del decorador podría hacer que el decorador maneje su MessageSecurityException y reinicialice el proxy real cuando sea capturado:

//Decorator 2 public class MyServiceProxyExceptionHandlingDecorator : IMyService { //This is the real proxy that might be faulted private realProxy = new RealProxy(); public void MyMethod() { try {realProxy.MyMethod(); } catch (ExceptionYouAreInterestedIn ex) { ReEstablishProxyIfNecessary(); realProxy.MyMethod(); //do it again } } private void ReEstablishProxyIfNecessary() { if(realProxy.CommunicationState == CommunicationState.Faulted) { realProxy.Abort(); realProxy = new RealProxy(); } } }



Sobre la base de la primera respuesta, se me ocurrió esta solución que genéricamente envuelve los proxies de cliente generados automáticamente por svcutil.exe:

public class ProxyWrapper<T> where T : ICommunicationObject { private T _service; public ProxyWrapper() { _service = CreateNewInstance(); } public void Invoke(Action<T> action) { try { action(_service); } catch (MessageSecurityException) { if (_service.State != CommunicationState.Faulted) { throw; } _service.Abort(); _service = CreateNewInstance(); action(_service); } } public TResult Invoke<TResult>(Func<T, TResult> func) { try { return func(_service); } catch (MessageSecurityException) { if (_service.State != CommunicationState.Faulted) { throw; } _service.Abort(); _service = CreateNewInstance(); return func(_service); } } private T CreateNewInstance() { Type type = typeof(T); return (T)type.GetConstructor(Type.EmptyTypes).Invoke(null); } }

Para usar esto, todo lo que necesitas hacer es:

ProxyWrapper<ServiceClient> client = new ProxyWrapper<ServiceClient>(); client.Invoke(s => s.SomeAction()); int val = client.Invoke<int>(s => s.ReturnsAnInteger());

Nota: Dado que solo estoy usando el constructor predeterminado para los proxies del cliente, eso es todo lo que admite.