10
votes

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.

4
This is basically the same question I asked here: stackoverflow.com/questions/494906/… Very interested to see solutions. I'd like to see a solution that uses the built-in WCF hooks, and doesn't involve changing the proxy class (since mine is autogenerated) - davogones
The Dasblonde download seems to be available here: dasblonde.net/downloads/Proxies.zip - Charlesdwm

4 Answers

5
votes

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().

5
votes

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.

0
votes

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

0
votes

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