Dot-Net

SCT 過期時續訂 WCF 客戶端?

  • February 5, 2016

我正在使用 WCF 到使用安全模式“TransportWithMessageCredential”的肥皂端點。

WCF 客戶端/伺服器使用 SCT(安全上下文令牌)來維護安全連接,並且它在一般情況下按預期工作。

但是,在一段時間不活動之後,SCT 將過期,並且下一次方法呼叫將導致 MessageSecurityException:

從另一方收到不安全或不正確安全的故障。故障程式碼和細節見內部FaultException

內部異常:

無法處理該消息。這很可能是因為操作“ http://tempuri.org/IMyService/MyMethod ”不正確,或者因為消息包含無效或過期的安全上下文令牌,或者因為綁定之間不匹配。如果服務由於不活動而中止通道,則安全上下文令牌將無效。為了防止服務過早中止空閒會話,請增加服務端點綁定的接收超時。

在隨後的呼叫中,當我看到 CommunicationState 出現故障時,我會更新連接。但是我找不到在進行方法呼叫之前先發製人地檢查 SCT 是否已過期的方法。

您可以使用委託來解決您的問題。這將允許安全地呼叫該操作,如果失敗,則擷取異常,構造一個新的服務實例並再次執行該操作。

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()一樣呼叫您的幫助程序類。

在第一個答案的基礎上,我提出了這個解決方案,它通常包裝由 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());

**注意:**由於我只使用客戶端代理的預設建構子,這就是所有這些支持。

引用自:https://stackoverflow.com/questions/479618