Удаление обработчика события при вызове службы wcf - PullRequest
0 голосов
/ 20 ноября 2010

Я недавно сталкивался с этим кодом:

    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); 
        } 
); 

}

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

Спасибо!

EDIT:

Я вызываю такой код из моей команды нажатия кнопки:

            _dataService.GetData(GetDataCompleted);

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

1 Ответ

0 голосов
/ 03 апреля 2011

Я думаю, что вы можете решить эту проблему путем реализации стратегии push-pull в своем коде.Я предлагаю что-то похожее на это:

 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;
        }  
     }           
 }

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

Во всяком случае, лично мне не нравится эта реализация для того, что вы пытаетесь достичь.Код довольно запутанный и затрудняет предвидение проблем, которые могут возникнуть.Убедитесь, что:

  • вы предоставляете способ прервать запрос и снова включить кнопку

  • код, который обновляет экран, выполняетсяпользовательский интерфейс

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...