WP7 - запутался в связи по сети, межпотоковом доступе и продолжении передачи - PullRequest
2 голосов
/ 04 апреля 2011

Я портирую приложение WPF на WP7, и в ходе этого процесса мне пришлось провести рефакторинг всего кода, который касается сети.Старый код использовал синхронные методы объекта WebRequest в фоновых потоках, но эти методы больше не существуют в WP7.

Результат вызывает недоумение и заставляет меня чувствовать, что я делаю что-то не так.Мне пришлось засорять свои представления кодом диспетчеризации потоков - единственная альтернатива, которую я вижу, состоит в том, чтобы предоставлять диспетчер нижним уровням приложения, что нарушило бы независимость от платформы и запутало границу пользовательского интерфейса.Я потерял способность совершать цепочечные вызовы по сети из петель и вместо этого вызывал обратные вызовы.Я потерял обработку ошибок try / catch и вместо этого везде использовал обратные вызовы OnSuccess и OnError.Теперь я всегда непреднамеренно выполняю код в фоновых потоках, которые вызываются обратными вызовами.Я с любовью помню дни, когда мне удавалось возвращать значения из методов.

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

Извиняюсь, если этот вопрос расплывчатый, я просто хотел бы знать, упускаю ли я здесь какую-то общую картину.

Ответы [ 2 ]

3 голосов
/ 05 апреля 2011

Это ограничение Silverlight, которое требует асинхронного доступа к сети (вызовы прокси WCF, WebClient, WebRequest и т. Д.).Все синхронные вызовы методов, зависящие от сети, были удалены из фреймворка.

Быть грубым: добро пожаловать в асинхронное программирование.Единственное, что вы сделали неправильно, это не сделали вызовы асинхронными, во-первых:)

Я не на 100% уверен в точных причинах, по которым MS удалил вызовы синхронизации из веб-зависимых объектов в Silverlight, ноЯ всегда слышу объяснения, основанные на одной или двух причинах в некоторой комбинации:

  • Браузеры спроектированы для асинхронных сетевых вызовов.Внедрение синхронных вызовов может привести к плохому поведению / поломке приложений / сбоям и т. Д.
  • Если бы они давали всем "легкий выход" из синхронных вызовов, мир был бы завален приложениями Silverlight, которые всегда зависали при выполнении каких-либо действий насеть, в результате чего Silverlight как платформа выглядит плохо.

При этом прокси WCF в Silverlight работают так, что они всегда выполняют обратный вызов в вызывающем потоке.Чаще всего это поток пользовательского интерфейса, то есть вам не нужно выполнять диспетчеризацию.Я не знаю, разделяют ли WebClient / WebRequest в Silverlight это поведение.

Что касается диспетчера, вы можете вместо этого использовать SynchronizationContext.Ссылочная реализация MVVM в руководстве MS Patterns and Practices Prism делает это - в хранилище (класс доступа к данным, который фактически обращается к абстрактной внешней службе), они имеют член SynchronizationContext, который инициализирован для System.Threading.SynchronizationContext.Current.,Это поток пользовательского интерфейса, если конструктор вызывается в потоке пользовательского интерфейса (так и должно быть).Все результаты вызовов службы затем обрабатываются с помощью mySynchronizationContext.Post.

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

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

Я должен согласиться с вами, прохождение продолжения сложно. Действительно полезный метод - заимствовать конструкцию C # yield return для создания машины, которая способна поддерживать состояние между асинхронными операциями. Для действительно хорошего объяснения см. Этот блог Джереми Ликнесса.

Лично я предпочитаю подход «меньше - больше», поэтому AsyncOperationService - это очень маленький кусок кода. Вы заметите, что он имеет единый обратный вызов как для успеха, так и для отказа, и нет интерфейсов для реализации только умеренного делегата Action<Action<Exception>>, который набирается как AsyncOperation, чтобы сделать его более удобным.

Основные шаги для кодирования этого: -

  • Код, как если бы синхронное выполнение было возможно
  • Создание методов, которые возвращают AsyncOperation fpr только наименьшую часть, которая должна быть асинхронной. Обычно некоторые WebRequest или WCF-вызовы, но заметьте, что достаточно, чтобы обойти бит асинхронности, см. Другой ответ для хорошего примера.
  • Преобразуйте синхронный «псевдо-код» в yeild эти AsyncOperations и измените вызывающий код на «Выполнить» в результате перечисления.

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

Что касается случайного запуска вещей в фоновом потоке, последний ответ включал в себя эту полезную AsyncOperation: -

public static AsyncOperation SwitchToUIThread()
{
    return (completed => Deployment.Current.Dispatcher.BeginInvoke(() => completed(null)));
}

Вы можете использовать это как последний yield в прогоне, чтобы гарантировать выполнение кода в обратном вызове completed в потоке пользовательского интерфейса. Также полезно «перевернуть», по-видимому, синхронный код для выполнения в потоке пользовательского интерфейса при необходимости.

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