#c# #silverlight #wcf
#c# #silverlight #wcf
Вопрос:
Я уже знаю, что вызовы служб WCF через Silverlight являются асинхронными. Я также знаю, что многие люди пытаются найти способы заставить их синхронизировать вызовы по разным глупым причинам (например, блокирование потока пользовательского интерфейса), и что такого следует избегать, как чумы, в целом.
Я просто хочу иметь возможность самостоятельно обрабатывать все потоки, поскольку обнаружил, что необходимость подключать / отсоединять все события ‘ * Completed’ — это большая дополнительная работа и огромная боль, особенно когда вы не знаете порядок вызовов и т.д. Кто-нибудь знает умный способ выполнять вызовы синхронизации и выполнять потоки самостоятельно?
Комментарии:
1. Почему вы отцепляете все
completed
события?2. Чтобы избежать утечек памяти. Короче говоря, служба ‘A’ может вызываться более чем в одном месте, и иногда у нее нет точно такого же обработчика для своего ‘Завершенного’ события. Но давайте избежим обсуждения дизайна / намерений и придерживаемся технической части вопроса….
3. Достаточно справедливо, но знание дизайна / намерений может повлиять на решение.
4. Согласен. проблема в том, что я могу придумать десятки более длинных решений, и лучше всего было бы обрабатывать потоки самостоятельно. —> Короче говоря, я пытаюсь настроить служебные вызовы результаты в отдельные сопрограммы, но все дополнительные типы, которые генерируются, делают это огромной проблемой. Отражение работает нормально, но все еще очень подробно, а затем возникает проблема с производительностью……
5. Вы пробовали Rx вместо того, чтобы пытаться синхронизировать вещи?
Ответ №1:
Учитывая, что вы не должны выполнять синхронные сетевые вызовы, вы не должны выполнять синхронные сетевые вызовы и не должны выполнять синхронные сетевые вызовы, если вы действительно, действительно знаете, что делаете, тогда вы действительно можете выполнять синхронные (блокирующие) вызовы, только если вы не находитесь в потоке пользовательского интерфейса .. Просто поймите, чтоэто официально не поддерживаемый сценарий (поэтому он не был так протестирован, как другие функции), но я пробовал его несколько раз, и он просто работает.
Все, что вам нужно сделать, это использовать [ServiceContract]
интерфейс (вместо клиентского класса) — тот, который предоставляет операции Begin / End — и вызвать EndXXX(BeginXXX(parameters, null, null))
, как показано в примере ниже (это страница с двумя элементами управления, Button
Click
событие которого привязано к Button_Click
обработчику, и TextBox
именем «txtDebug»куда код записывает результаты.
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.AddToDebug("In Button_Click");
ThreadPool.QueueUserWorkItem(delegate
{
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
ServiceReference1.Service1 asInterface = client;
this.AddToDebug("Calling server "synchronously"...");
int result = asInterface.EndAdd(asInterface.BeginAdd(45, 67, null, null));
this.AddToDebug("Result: {0}", result);
client.CloseAsync();
});
}
private void AddToDebug(string text, params object[] args)
{
if (args != null amp;amp; args.Length > 0)
{
text = string.Format(text, args);
}
text = string.Format("[{0} - {1}] {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"), text);
this.Dispatcher.BeginInvoke(() => this.txtDebug.Text = this.txtDebug.Text text Environment.NewLine);
}
}
Теперь, если вы хотите сделать это из потока пользовательского интерфейса, тогда действительно нет способа заблокировать и дождаться ответа (поскольку ответ должен быть возвращен и в потоке пользовательского интерфейса). И если вас устраивает шаблон Begin / End, вы все равно можете выполнять асинхронные вызовы, но не беспокоясь о утечке обработчиков событий.
Комментарии:
1. Да, я бы никогда не хотел блокировать поток пользовательского интерфейса, просто избегайте накладных расходов «обычного» подхода Silverlight. Похоже, это приведет меня в правильном направлении…
2. Вы действительно пробовали это в Silverlight? Поскольку Silverlight не поддерживает AsyncWaitHandles в реализациях IAsyncResult, трудно понять, как это будет работать? Я не говорю, что это категорически не так, я сам не пробовал, но я был бы очень удивлен, если бы это произошло.
3. Да, я попробовал это, прежде чем ответить. Как я уже сказал, это не поддерживается, но в простых случаях, которые я пробовал, это сработало, так что это хак «используйте на свой страх и риск».
4. Понял. Я думаю, иногда взломы неизбежны. 🙂
Ответ №2:
Решений, которые полагаются на блокировку потока (любого потока, а не только потока пользовательского интерфейса), лучше избегать. Потоки — это дорогостоящие ресурсы, а потоки пула потоков — ограниченный ресурс. Вот почему сетевые API имеют семантику обратного вызова на первом месте.
Я согласен с Карлосом , что первое , что нужно сделать , это переключиться на .Интерфейс СЕТЕВОГО асинхронного шаблона, предоставляемый службой вместо ужасного, основанного на событиях. (Подход, основанный на событиях, предназначен для упрощения работы разработчиков пользовательского интерфейса, которые «мыслят событиями»). Если ваша служба называется «Service1», ваш клиентский класс будет называться «Service1Client». Однако этот класс также будет поддерживать интерфейс с именем «Service1», который будет иметь начальную / конечную версии OperationContracts.
«умный способ выполнения вызовов синхронизации»
Без блокировки потока это невозможно. Однако синхронность выполнения ряда задач на самом деле не является обязательным требованием. Мы просто хотим убедиться, что ряд задач выполняется последовательно. Вы можете сделать это, просто вызвав следующую задачу из метода обратного вызова предыдущей задачи, но вложение становится небольшой проблемой.
Взгляните на эту серию статей, возможно, начиная с той, что на .ЧИСТЫЙ асинхронный шаблон. К сожалению, статья WCF все еще находится в стадии разработки, но я действительно должен опубликовать ее в ближайшее время, этот материал часто появляется здесь.
Ответ №3:
Что, если вы перенесете вызов в другую функцию, и эта функция будет находиться в спящем режиме, пока не вернется асинхронный вызов?
Комментарии:
1. Это в основном то, что я делаю сейчас, но это все равно не позволяет избежать накладных расходов на код при подключении / отключении событий.