views:

1973

answers:

4

I am using WCF to a soap endpoint using security mode "TransportWithMessageCredential".

The WCF client/server uses SCT (Security Context Token) to maintain a secure connection, and it is working as intended in the general case.

However, after a period of inactivity, the SCT will be expired and the next method call will cause a MessageSecurityException:

An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail

Inner exception:

The message could not be processed. This is most likely because the action 'http://tempuri.org/IMyService/MyMethod' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.

On subsequent calls, I renew the connection when I see that CommunicationState is Faulted. But I cannot find a way to preemptively check whether the SCT has expired before making my method call.

A: 

You might be able to use the decorater pattern to handle exceptions with WCF proxies. If this path is open to you, you can consider something like this set-up which will handle the proxy faulting and re-initialise it for callers. Subsequent exceptions will be thrown up to the caller.

//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();
    }
  }
}

An different version of the decorator could have the decorator handling your MessageSecurityException, and re-initialising the real proxy when it is caught:

//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();
    }
  }
}
Jimmy McNulty
Your pattern will not work. The entire problem is that the "realProxy" only becomes in a faulted state AFTER the call to MyMethod, not before. The question is how to preemtively find out whether the proxy will fail, since the client must obviously know something about its SCT expiration.
mbp
I'm not sure you can find out that a method will error with the SCT error before you try calling it. I have ammended my post to show how to handle the exception for clients so they don't have to.
Jimmy McNulty
+3  A: 

You could resolve your issues by using delegates. This will allow to safely invoke the action and, if fails, catch the exception, construct a new service instance and perform the action again.

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);
  }   
 }
}

You could then call your helper class like Service.Invoke(s => s.Method()); to invoke the IService.Method().

troethom
A: 

Take a look at this post where you can download a proxy wrapper that does a retry when the session expires.

http://www.dasblonde.net/2008/04/24/MyProxyWrapperAndTheEVILSUOFile.aspx

Jonathan Parker
A: 

Building on the first answer, I came up with this solution that generically wraps the auto-generated client proxies created by 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);
    }
}

To use this, all you need to do is:

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

Note: Since I'm only using the default constructor for the client proxies, that's all this supports.

steve.platz