在wcf服务调用上删除事件处理程序

时间:2010-11-19 21:09:09

标签: c# wcf

我最近遇到过这段代码:

    public static class ClientBaseExtender 
{ 
    /// <summary> 
    /// Tries to execute async service call. If <see cref="TimeoutException"/> occured retries again. 
    /// </summary> 
    /// <typeparam name="TChannel">ServiceClient class.</typeparam> 
    /// <typeparam name="TArgs">Type of service client method return argument.</typeparam> 
    /// <param name="client">ServiceClient instance.</param> 
    /// <param name="tryExecute">Delegate that execute starting of service call.</param> 
    /// <param name="onCompletedSubcribe">Delegate that subcribes an event handler to the OnCompleted event of the service client method.</param> 
    /// <param name="onCompleted">Delegate that executes when service call is succeeded.</param> 
    /// <param name="onError">Delegate that executes when service call fails.</param> 
    /// <param name="maxAttempts">Maximum attempts to execute service call before error if <see cref="TimeoutException"/> occured (by default 5).</param> 
    public static void ExecuteAsyncRepeatedly<TChannel, TArgs>(this ClientBase<TChannel> client, Action tryExecute, 
                                                               Action<EventHandler<TArgs>> onCompletedSubcribe, EventHandler<TArgs> onCompleted, 
                                                               EventHandler<TArgs> onError, int maxAttempts) 
        where TChannel : class 
        where TArgs : AsyncCompletedEventArgs 
    { 
        int attempts = 0; 
        var serviceName = client.GetType().Name; 

        onCompletedSubcribe((s, e) => 
                                { 
                                    if (e.Error == null) // Everything is OK 
                                    { 
                                        if (onCompleted != null) 
                                            onCompleted(s, e); 

                                        ((ICommunicationObject)client).Close(); 
                                        Debug.WriteLine("[{1}] Service '{0}' closed.", serviceName, DateTime.Now); 
                                    } 
                                    else if (e.Error is TimeoutException) 
                                    { 
                                        attempts++; 

                                        if (attempts >= maxAttempts) // Final timeout after n attempts 
                                        { 
                                            Debug.WriteLine("[{2}], Final Timeout occured in '{0}' service after {1} attempts.", serviceName, attempts, DateTime.Now); 

                                            if (onError != null) 
                                                onError(s, e); 
                                            client.Abort(); 

                                            Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now); 
                                            return; 
                                        } 

                                        // Local timeout 
                                        Debug.WriteLine("[{2}] Timeout occured in '{0}' service (attempt #{1}).", serviceName, attempts, DateTime.Now); 

                                        Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now); 
                                        tryExecute(); // Try again. 
                                    } 
                                    else 
                                    { 
                                        if (onError != null) 
                                            onError(s, e); 
                                        client.Abort(); 
                                        Debug.WriteLine("[{1}] Service '{0}' aborted.", serviceName, DateTime.Now); 
                                    } 
                                }); 

        Debug.WriteLine("[{2}] Attempt #{0} to execute call to '{1}' service.", attempts + 1, serviceName, DateTime.Now); 
        tryExecute(); // First attempt to execute 
    } 
}

    public void GetData()
    {
    var client = new MyServiceClient(); 
     client.ExecuteAsyncRepeatedly(() => client.MyOperationAsync(...), 
    (EventHandler<MyOperationCompletedEventArgs> handler)                                        =>client.MyOperationCompleted += handler, 
    (s, e) => // OnCompleted 
        { 
            Do(e.Result); 
        }, 
    (s, e) => // OnError 
        { 
            HandleError(e.Error); 
        } 
); 

}

问题是,我有一个按钮可以关闭此代码。当多次按下按钮时,处理程序会一次又一次地被添加。这是一个问题,因为代码会在用户按下按钮时触发多次。如何在此代码中删除使用lambda表达式创建的处理程序,以便它只运行一次?

谢谢!

编辑:

我正在通过我的按钮点击命令调用这样的代码:

            _dataService.GetData(GetDataCompleted);

        private void GetDataComplete(Data data)
    {
        //do something with data        }

1 个答案:

答案 0 :(得分:0)

我认为您可以通过在代码隐藏中实施推拉策略来解决它。我提出类似的建议:

 bool _requestPending;
 readonly object _lock = new object();

 void OnClick (...)
 {
     lock(_lock)
     {
        if (_requestPending == false)
        {
            _dataService.GetData(GetDataCompleted);
            _requestPending = true;
        }
     }
 }
 private void GetDataComplete(Data data)
 {
     lock(_lock)
     {
        try
        {
           //do something with data 
        }
        finally
        {
           _requestPending = false;
        }  
     }           
 }

更好的是,在您有待处理请求时停用UI按钮。从不同的线程访问和修改_requestPending时,你不会遇到任何并发问题,但如果服务响应足够快,你仍然会遇到竞争条件,所以更好地同步两个代码块。

无论如何,就我个人而言,我个人并不喜欢这个实现。代码非常混乱,很难预见可能出现的问题。确保:

  • 您提供了一种中止请求的方法 并再次重新启用该按钮

  • 更新屏幕的代码是 由UI线程执行