.net 在SCT过期时续订WCF客户端?

.net 在SCT过期时续订WCF客户端?,.net,wcf,performance,.net,Wcf,Performance,我正在使用安全模式“TransportWithMessageCredential”将WCF用于soap端点 WCF客户机/服务器使用SCT(安全上下文令牌)来维护安全连接,并且它在一般情况下按预期工作 但是,在一段时间不活动后,SCT将过期,下一个方法调用将导致MessageSecurityException: 从另一方收到未担保或未正确担保的故障。有关故障代码和详细信息,请参见内部FaultException 内部异常: 无法处理该消息。这很可能是因为操作“”不正确,或者是因为消息包含无效或过

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

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

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

从另一方收到未担保或未正确担保的故障。有关故障代码和详细信息,请参见内部FaultException

内部异常:

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


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

您可以使用装饰器模式处理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();
    }
  }
}
不同版本的decorator可能会让decorator处理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();
    }
  }
}

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

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);
        }           
    }
}
使用系统;
使用System.ServiceModel;
使用System.ServiceModel.Security;
公共静态类服务
{
专用静态设备服务;
公共静态无效调用(操作)
{
尝试
{
行动(服务);
}
捕获(MessageSecurityException)
{
if(_service.State!=CommunicationState.Faulted)
{
投掷;
}
_service.Abort();
_service=CreateFreshInstance();
行动(服务);
}           
}
}

然后可以调用助手类,如
Service.Invoke(s=>s.Method())
调用IService.Method()。

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


在第一个答案的基础上,我提出了这个解决方案,它通常包装由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,其中T:ICommunicationObject
{
私人电讯服务;;
公共代理包装器()
{
_service=CreateNewInstance();
}
公共无效调用(操作)
{
尝试
{
行动(服务);
}
捕获(MessageSecurityException)
{
if(_service.State!=CommunicationState.Faulted)
{
投掷;
}
_service.Abort();
_service=CreateNewInstance();
行动(服务);
}
}
公共TResult调用(Func Func)
{
尝试
{
返回func(_服务);
}
捕获(MessageSecurityException)
{
if(_service.State!=CommunicationState.Faulted)
{
投掷;
}
_service.Abort();
_service=CreateNewInstance();
返回func(_服务);
}
}
私有T CreateNewInstance()
{
类型=类型(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());
ProxyWrapper客户端=新的ProxyWrapper();
调用(s=>s.SomeAction());
int val=client.Invoke(s=>s.ReturnsAnInteger());

注意:因为我只使用客户机代理的默认构造函数,所以这些都支持

你的模式行不通。整个问题在于,“realProxy”仅在调用MyMethod之后,而不是之前,才会处于故障状态。问题是如何先发制人地确定代理是否会失败,因为客户机显然必须知道有关其SCT过期的一些信息。我不确定在您尝试调用它之前,您是否能发现某个方法会因SCT错误而出错。我在我的帖子中展示了如何为客户处理异常,这样他们就不必这样做。这基本上和我在这里问的问题相同:非常有兴趣看到解决方案。我希望看到一个使用内置WCF钩子的解决方案,并且不涉及更改代理类(因为我的是自动生成的)。Dasblonde下载似乎在这里可用:未找到。无法下载代理包装器的源代码(会话过期后重试)。在
github