Silverlight 4: уровень извлечения данных вызова REST API?

#c# #silverlight #data-binding #rest

#c# #silverlight #привязка данных #rest

Вопрос:

Я работаю в .NET 4 и SL 4. Я хочу абстрагироваться от части поиска данных в моем DAL из кода моей страницы silverlight. В идеале в собственную DLL в качестве уровня интерфейса между моим приложением silverlight и вызовами REST API. Я не собираюсь использовать службы RIA, поскольку у меня уже есть существующий DAL, который использует DLL, которая выполняет вызовы REST API.

Проблема заключается в асинхронном процессе обратного вызова «WebClient». Я знаю, что могу использовать класс WebClient для выполнения вызова REST, а затем зарегистрировать асинхронный обработчик, чтобы просто привязать результаты этого вызова к пользовательскому интерфейсу. Но в моем случае я хочу абстрагировать это в свою собственную DLL. В основном …. делая это синхронным.

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

Кто-нибудь может указать мне на образец / учебник, где делается что-то подобное?

RIA вызывает метод отдельной библиотеки DLL для сбора данных IEnumerable

Этот метод вызывает REST API для извлечения данных, затем возвращает это IEnumerable в RIA и привязывается к пользовательскому интерфейсу.

Комментарии:

1. Привяжите свой пользовательский интерфейс к свойству, которое возвращает ваш IEnumerable через ObservableCollection<T> . Таким образом, пользовательский интерфейс может быть привязан к пустому списку, и по мере того, как данные возвращаются в асинхронном режиме, просто обновляйте себя соответствующим образом.

Ответ №1:

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

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

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

Преобразование синхронного в асинхронный

Прочитали этот блог о преобразовании синхронного кода в асинхронный. Прочитав это, теперь давайте просто представим, что ваш код использует синхронный метод в вашей новой библиотеке DLL с именем DownloadYourDataObjects , который имеет эту воображаемую сигнатуру:-

  public IEnumerable<YourDataObject> DownloadYourDataObjects(Uri source);
  

Внутренне он используется WebClient для загрузки строки из базовой службы REST и преобразует ее в набор YourDataObject экземпляров. Воображаемый синхронный код для отображения этого набора данных может быть:-

  private void btnLoadMyData_Click(object sender, RoutedEventArgs e)
 {
      try
      {
          LoadMyData();
      }
      catch (Exception err)
      {
          // Oops something bad happened show err.
      }
 }

 private void LoadMyData()
 {
      DataItemsListBox.ItemsSource = DownloadYourDataObjects(someUri);
 }
  

Поскольку Silverlight WebClient является асинхронным, нам нужно преобразовать всю эту цепочку кода для работы асинхронным образом.

Используя AsyncOperationService из блога, нам сначала нужно преобразовать DownloadYourDataObjects , чтобы вместо этого возвращать AsyncOperation . У этого была бы подпись, подобная этой (смотрите позже идею реализации):-

 public AsyncOperation DownloadYourDataObjects(Uri source, Action<IEnumerable<YourDataObject>> returnResult);
  

Тогда код использования выглядел бы примерно так:-

  private void btnLoadMyData_Click(object sender, RoutedEventArgs e)
 {
      LoadMyData().Run(err =>
      {
          if (err != null)
          {
              // Oops something bad happened show err.
          }
      });
 }

 private IEnumerable<AsyncOperation> LoadMyData()
 {
      yield return DownloadYourDataObjects(someUri, result =>
      {
          DataItemsListBox.ItemsSource = resu<
      });
 }
  

Это может показаться немного ОТТ, но на самом деле это ненамного больше кода, чем исходная «синхронная» версия. В этом простом случае LoadMyData требовалось выполнить только одну операцию. Более сложная версия LoadMyData может содержать множество других операций, которые также должны быть асинхронными. В таком случае эти операции были бы просто другими yield точками в коде, базовая логическая структура LoadMyData которых не сильно изменилась бы по сравнению с исходной синхронной версией.

Вот пример реализации DownloadYourDataObjects , которую будет предоставлять ваша DLL.

  public AsyncOperation DownloadYourDataObjects(Uri source, Action<IEnumerable<YourDataObject>> returnResult)
 {
     return (completed) =>
     {
         WebClient client = new WebClient();
         client.DownloadStringCompleted  = (s, args) =>
         {
             try
             {
                 returnResult(ConvertStringToYourDataObjects(args.Result));
                 completed(null);
             }
             catch (Exception err)
             {
                 completed(err);
             }
         };
         client.DownloadStringAsync(source);
     };
 }