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