SCT过期后续订WCF客户端?

时间:2009-01-26 12:21:33

标签: .net wcf performance

我使用安全模式“TransportWithMessageCredential”将WCF用于soap端点。

WCF客户端/服务器使用SCT(安全上下文令牌)来维护安全连接,并且它在一般情况下正常工作。

但是,在一段时间不活动之后,SCT将过期,下一个方法调用将导致MessageSecurityException:

  

从另一方收到了无担保或不正确安全的故障。请参阅内部FaultException以获取故障代码和详细信息

内部异常:

  

无法处理邮件。这很可能是因为操作“http://tempuri.org/IMyService/MyMethod”不正确,或者因为邮件包含无效或过期的安全上下文令牌,或者因为绑定之间存在不匹配。如果服务因不活动而中止通道,则安全上下文令牌将无效。要防止服务中止空闲会话,请过早增加服务端点绑定的接收超时。

在后续调用中,当我看到CommunicationState出现故障时,我会更新连接。但在进行方法调用之前,我找不到预先检查SCT是否已过期的方法。

4 个答案:

答案 0 :(得分:5)

您可以使用代理解决您的问题。这将允许安全地调用操作,如果失败,则捕获异常,构造新的服务实例并再次执行操作。

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

然后你可以调用你的助手类Service.Invoke(s => s.Method());来调用IService.Method()。

答案 1 :(得分:3)

在第一个答案的基础上,我提出了这个解决方案,它通常包装由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);
    }
}

要使用它,您需要做的就是:

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

注意:由于我只使用客户端代理的默认构造函数,所以这一切都支持。

答案 2 :(得分:0)

您可以使用decorater模式来处理WCF代理的异常。如果此路径对您开放,您可以考虑这样的设置,它将处理代理故障并为呼叫者重新初始化它。后续异常将被调用给调用者。

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

装饰器的不同版本可能让装饰器处理MessageSecurityException,并在捕获时重新初始化真实代理:

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

答案 3 :(得分:0)

看一下这篇文章,你可以下载一个代理包装器,在会话到期时重试。

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