Шаблон для правильного удаления обратных вызовов WCF при сбое - PullRequest
1 голос
/ 08 ноября 2010

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

Дьявол подробно, поскольку синхронизация необходима при добавлении, удалении и перечислении элементов списка. В настоящее время я использую этот шаблон:

class Foo : IDisposable
{
    private static readonly List<Foo> _Connections = new List<Foo> ();
    private readonly IFooCallback CallbackChannel;

    internal Foo ()
    {
        CallbackChannel = OperationContext.Current.GetCallbackChannel<IFooCallback> ();

        lock (_Connections) {
            _Connections.Add (this);
            OperationContext.Current.Channel.Closing += (s, e) => Dispose ();
            OperationContext.Current.Channel.Faulted += (s, e) => Dispose ();
        }
    }

    public void Dispose ()
    {
        lock (_Connections) {
            _Connections.Remove (this);
        }
    }

    private void RaiseCallback ()
    {
        List<Foo> connections;
        lock (_Connections) {
            connections = new List<Foo> (_Connections);
        }
        foreach (var con in connections) {
            try {
                con.CallbackChannel.SomeCallback ();
            }
            catch (CommunicationException) {
                OperationContext.Current.Channel.Abort ();
            }
            catch (TimeoutException) {
                OperationContext.Current.Channel.Abort ();
            }
        }
    }
}

Моя идея:

  1. Статический список экземпляров, каждый экземпляр хранит канал CB.
  2. Экземпляр удаляется, когда канал закрыт или прерван.
  3. При обратном вызове создается копия списка (синхронно) и нумеруется (не синхронизируется).
  4. При сбое обратного вызова канал прерывается.

Сбой обратного вызова вызывает прерывание канала, что, в свою очередь, вызывает удаление и удаление из списка. Это может произойти или не произойти в одном и том же потоке (это не может быть гарантировано, поскольку Dispose может быть вызван в любое время из-за другого события).

У меня вопрос: является ли это общим шаблоном для хранения экземпляров и обработки ошибок обратного вызова, или как его можно улучшить? Копирование списка перед перечислением в RaiseCallback - это ошибка, или это правильно?

...