Обновление клиента WCF после истечения срока действия SCT? - PullRequest
9 голосов
/ 26 января 2009

Я использую WCF для конечной точки мыла, используя режим безопасности "TransportWithMessageCredential".

Клиент / сервер WCF использует SCT (маркер контекста безопасности) для поддержания безопасного соединения и работает в обычном режиме, как и предполагалось.

Однако после периода бездействия срок действия SCT истечет, и следующий вызов метода вызовет исключение MessageSecurityException:

Необеспеченная или неправильно защищенная ошибка получена от другой стороны. См. Внутреннее исключение FaultException для получения кода ошибки и подробного описания

Внутреннее исключение:

Сообщение не может быть обработано. Скорее всего, это потому, что действие 'http://tempuri.org/IMyService/MyMethod' является неправильным, или потому что сообщение содержит недопустимый токен или токен контекста безопасности с истекшим сроком действия или из-за несоответствия между привязками. Маркер контекста безопасности будет недействительным, если служба прервет канал из-за неактивности. Чтобы предотвратить прерывание незанятыми сеансами службы преждевременно, увеличьте время ожидания приема для привязки конечной точки службы.

При последующих вызовах я возобновляю соединение, когда вижу, что CommunicationState неисправен. Но я не могу найти способ превентивно проверить, не истек ли срок действия SCT, прежде чем делать мой вызов метода.

Ответы [ 4 ]

5 голосов
/ 29 января 2009

Вы можете решить свои проблемы с помощью делегатов. Это позволит безопасно вызвать действие и, в случае сбоя, перехватить исключение, создать новый экземпляр службы и снова выполнить действие.

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

3 голосов
/ 03 августа 2010

Основываясь на первом ответе, я пришел к этому решению, которое в общем случае оборачивает автоматически сгенерированные клиентские прокси, созданные 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());

Примечание: Поскольку я использую конструктор по умолчанию только для клиентских прокси, это все, что поддерживается.

0 голосов
/ 08 марта 2009

Взгляните на этот пост, где вы можете скачать прокси-оболочку, которая повторяет попытку после окончания сеанса.

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

0 голосов
/ 27 января 2009

Возможно, вы сможете использовать шаблон 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();
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...