簡體   English   中英

在WCF服務調用上刪除事件處理程序

[英]Removing the event handler on wcf service call

我最近遇到了以下代碼:

    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        }

我認為您可以通過在背后的代碼中實施推挽策略來解決此問題。 我提出類似的建議:

 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線程執行更新屏幕的代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM