.net 模式以在发生故障时正确删除WCF回调

.net 模式以在发生故障时正确删除WCF回调,.net,wcf,design-patterns,callback,.net,Wcf,Design Patterns,Callback,我有一个类,它存储连接实例的静态列表。在回调时,将调用列表中的每个实例,如果调用失败,将从列表中删除该实例 魔鬼的细节,因为同步时需要添加,删除和枚举列表项。我目前正在使用这种模式: class Foo : IDisposable { private static readonly List<Foo> _Connections = new List<Foo> (); private readonly IFooCallback CallbackChannel

我有一个类,它存储连接实例的静态列表。在回调时,将调用列表中的每个实例,如果调用失败,将从列表中删除该实例

魔鬼的细节,因为同步时需要添加,删除和枚举列表项。我目前正在使用这种模式:

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 ();
            }
        }
    }
}
class Foo:IDisposable
{
私有静态只读列表_Connections=new List();
专用只读IFooCallback回调回调通道;
内部Foo()
{
CallbackChannel=OperationContext.Current.GetCallbackChannel();
锁定(_连接){
_连接。添加(此);
OperationContext.Current.Channel.Closing+=(s,e)=>Dispose();
OperationContext.Current.Channel.Faulted+=(s,e)=>Dispose();
}
}
公共空间处置()
{
锁定(_连接){
_连接。移除(此);
}
}
私有void RaiseCallback()
{
列出连接;
锁定(_连接){
连接=新列表(_连接);
}
foreach(连接中的var con){
试一试{
con.CallbackChannel.SomeCallback();
}
捕获(通信异常){
OperationContext.Current.Channel.Abort();
}
捕获(超时异常){
OperationContext.Current.Channel.Abort();
}
}
}
}
我的想法是:

  • 静态实例列表,每个实例存储CB通道
  • 当通道关闭或中止时,实例将被删除
  • 在回调时,将创建(同步)和枚举(不同步)列表的副本
  • 当回调失败时,通道将中止
  • 失败的回调会导致通道中止,从而导致Dispose并从列表中删除。这可能发生在同一个线程上,也可能不发生在同一个线程上(由于不同的事件可能随时引发Dispose,因此无法保证)


    我的问题是,这是处理实例存储和回调错误处理的常见模式,还是可以改进?在RaiseCallback中枚举之前复制列表是错误,还是正确?

    在未将事件设置为调用
    Dispose()
    的情况下,是否也调用了
    Dispose()
    ?我相信当WCF服务实现IDisposable时,它会被自动调用。真的吗?很好,我不知道。你能提供一个消息来源吗?