10/10/2010 12:07:16 PM

Я не знаю, как вам, но мне лично (да и не только мне) работа с шаблоном IAsyncResult всегда доставляла головную боль. Все эти BeginOperationName, EndOperationName, Callbacks… Обработка ошибок там…
Нет, я не говорю что IAsyncResult – это плохо. Это хорошо и полезно и всё такое, просто работать с этим достаточно сложно.

Было сложно, пока не появился Rx Winking smile

Что нам нужно чтобы, например, асинхронно получить данные с веб-сервиса или веб-странички?
Да практически ничего:

   1:  public static class WebRequestExtensions
   2:  {
   3:      public static IObservable<WebResponse> ToObservable(this WebRequest request)
   4:      {
   5:          if (request == null) throw new ArgumentNullException("request");
   6:   
   7:          var getResponse = Observable
   8:              .FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse);
   9:   
  10:          return getResponse();
  11:      }
  12:   
  13:      public static string GetContentAsString(this WebResponse response)
  14:      {
  15:          if (response == null) throw new ArgumentNullException("response");
  16:   
  17:          using (var stream = response.GetResponseStream())
  18:          using (var reader = new StreamReader(stream, false))
  19:              return reader.ReadToEnd();
  20:      }
  21:   
  22:  }

Вся “магия” заключена в методе ToObservable(..), конкретно – в строках 7 и 8.
Вот и всё! Это действительно всё, что нам нужно сделать для работы с IAsyncResult. Следующий метод – GetContentAsString(..) – просто вспомогательный метод, позволяющий получить строку ответа из потока, я привёл его просто потому, что буду его использовать дальше в примере:

   1:  public static IObservable<string> GetObservableWebContent(string url)
   2:  {
   3:      var request = WebRequest.Create(new Uri(url));
   4:   
   5:      return request
   6:          .ToObservable()
   7:          .Select(x => x.GetContentAsString());
   8:  }

Итак, теперь для любого URL мы можем получить IObservable, который будет “уведомлен” когда результат будет готов. Причём результат мы уже имеем в виде строки, то есть, он готов к обработке.

Для начала просто выведем его на экран:

   1:  public static void PrintContentAsync(string url)
   2:  {
   3:      var observable = GetObservableWebContent(url)
   4:          .Subscribe(x => { Console.WriteLine(x); });
   5:  }

Но стоп, что если URL неправильный? Или сервер не отвечает? Или происходит ещё что-то неожиданное?
Тогда нам просто нужно сделать обработку ошибок:

   1:  public static void PrintContentCatchError(string url)
   2:  {
   3:      GetObservableWebContent(url)
   4:          .Subscribe(
   5:              x => { Console.WriteLine(x); },
   6:              e => { throw e; });
   7:  }

Здесь я в строке 6 передаю Action-обработчик исключения. Я-то просто выкидываю это исключение, но вы-то можете поступить как угодно! Более умно, например Smile
Библиотека Rx содержит метод Catch<TException>(..), позволяющий обработать исключение без разрывания цепочки (например, можно  попробовать отследить таким образом какой-нибудь SessionTimeout, возобновить сессию и повторить попытку).

Но что если, даже имея такой вот замечательный observer я всё же хочу выполнить операцию синхронно? Что если мне нужно здесь и сейчас дождаться получения результата, заморозить UI, остановить время и мир до тех пор, пока ценные данные не будут получены?
В Случае с IAsyncResult я мог просто сделать что-то вроде: var result = EndOperationName(BeginOperationName(…));

Но и здесь всё гораздо проще (строка номер 4):

   1:  public static void PrintContentSync(string url)
   2:  {
   3:      var content = GetObservableWebContent(url)
   4:          .Single();
   5:   
   6:      Console.WriteLine(content);
   7:  }

Словом, при наличии IObservable жизнь становится намного проще и легче, чем при наличии просто event’ов, IAsyncResult’ов и т.д.
Причём немаловажно то, что когда у меня есть IObservable я просто пишу свою бизнес-логику и мне уже совершенно не важно, что там было изначально: пара-тройка event’ов ли (как в случае с перетаскиванием объекта из предыдущего постинга), IAsyncResult ли, что-то ещё или всё это скомбинированное вместе…

Comments (1) -

11/27/2010 4:14:40 AM

Amir Khan Vs Marcos Maidana

nice blog its really awesome.

Amir Khan Vs Marcos Maidana United States

Comments are closed

Powered by BlogEngine.NET 2.5.0.6

About the author

Alexey Raga Alexey Raga
.NET software developer.

E-mail me Send mail

Twitter

Widget Twitter not found.

Root element is missing.X


Recent posts

Archive

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2012

Sign in