Kategorie szkoleń | Egzaminy | Kontakt
  • 1
  • 2
  • 124

Odpowiedź (1)

  • 5
  • WCF Services

W przypadku usługi WCF Services jest to dosyć proste, bo wystarczy zaznaczyć opcję Generate task-based Operations przy dodawaniu odwołania do usługi za pomocą Add Service Reference:

 

Service Reference

 

Po zaznaczeniu tej opcji, generator klasy proxy wygeneruje metody z użyciem klasy Task i będzie je można wywołać asynchronicznie za pomocą async-await.

 

  • XML Web Services

W przypadku "starych" usług XML Web Services nie ma takiej opcji. Generatora proxy do XML Web Services generuje co prawda metody asynchroniczne, ale oparte o Event-based Asynchronous Pattern (w skrócie EAP).  

Wzorzec EAP opiera się na parze:

- [Operation]Async - metoda asynchroniczna

- [Operation]Completed - zdarzenie wywoływane po zakończeniu metody asynchronicznej

Więcej na temat EAP można znaleźć w msdn.

 

Operacje async-await współpracują natomiast ze wzorcem Task Event Pattern (w skrócie TAP).

Na szczęście istnieje sposób na przekształcenie EAP w TAP. Jednak tworzenie dla każdej metody usługi sieciowej takiej konwersji jest bardzo pracochłonne, zwłaszcza jeśli tych operacji jest sporo.

Dlatego utworzyłem prosty szablon, który umożliwia szybkie i łatwe opakowanie metod w async-await:

 

 private static TaskCompletionSource<T> CreateSource<T>(object state)
        {
            return new TaskCompletionSource<T>(
                state, TaskCreationOptions.None);
        }

        private static void TransferCompletion<T>(
         TaskCompletionSource<T> tcs, T e,
         Func<T> getResult, Action unregisterHandler)
             where T : AsyncCompletedEventArgs
        {
            if (e.Error != null)
            {
                tcs.TrySetException(e.Error);
            }
            else if (e.Cancelled)
            {
                tcs.TrySetCanceled();
            }
            else
            {
                tcs.TrySetResult(getResult());
            }
            if (unregisterHandler != null) unregisterHandler();

         
        }

 

Zwracam uwagę na wykorzystanie generic'ów.

Teraz można z niego skorzystać. Oto przykład:

 

 public Task<LoginCompletedEventArgs> LoginAsyncTask(string userName, string password)
        {
            var tcs = CreateSource<LoginCompletedEventArgs>(null);
            client.LoginCompleted += (sender, e) => TransferCompletion(tcs, e, () => e, null);
            client.LoginAsync(userName, password);
            return tcs.Task;
        }

 

W podobny sposób opakowujemy wszystkie metody usługi. Co prawda nie jest to pełny automat, bo wymaga od programisty pokrycia metod, ale i tak pozwala zaoszczędzić sporo kodu i czasu.

Może w przyszłości napiszę pełny automat z wykorzystaniem Roslyn. :)

 

 

 

  • Odpowiedział
  • @ | 03.09.2014
  • TRENER ALTKOM AKADEMII
Komentarze