Вызов асинхронного веб-сервиса - PullRequest
3 голосов
/ 31 августа 2010

Длинное сообщение .. извините

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

О моей ситуации;Я представляю пользователю страницу, которая будет содержать несколько разных ретрансляторов, показывающих некоторую информацию, основанную на результате нескольких вызовов веб-сервиса.Я хотел бы, чтобы данные вводились с панелью обновления (которая будет запрашивать таблицу результатов один раз каждые две или три секунды, пока она не найдет результаты), поэтому я действительно хотел бы отобразить страницу, а затем, когда данные "готов "это показано

На странице запрашивается информация для рендеринга контроллера, и контроллер проверяет таблицу результатов, чтобы увидеть, есть ли что-то, что можно найти.Если конкретные данные не найдены, он вызывает метод GetData () в WebServiceName.cs.GetData ничего не возвращает, но должен запустить асинхронную операцию, которая получает данные от веб-службы.Контроллер возвращает значение null, а UpdatePanel ожидает следующего запроса.

Когда эта операция будет завершена, она сохранит данные в соответствующем месте в БД, где контроллер найдет их в следующий раз, когда страница запросит их.,

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

Итак, текущий код, который находится на page.aspx:

Thread t = new Thread(new ThreadStart(CreateService));
        t.Start();
    }

    void CreateService()
    {
        ServiceName serviceName = new ServiceName(user, "12345", "MOVING", "Apartment", "5100", "0", "72", "Bill", "rate_total", "1", "103", "serviceHost", "password");

    }

AtСначала я подумал, что решение состоит в том, чтобы использовать Begin [Method] и End [Method], но, похоже, они не были сгенерированы.Я подумал, что это хорошее решение, поэтому я был немного расстроен, когда они не появились ... есть ли шанс, что я мог пропустить флажок или что-то подобное при добавлении веб-ссылок?

Не знаюЯ хочу использовать [Method] Async, так как это останавливает отображение страницы до тех пор, пока [Method] AsyncCompleted не будет вызван из того, что я понял.

Вызов, который я собираюсь сделать, не сильно загружает процессор, яЯ просто жду на веб-сервисе, сидящем на медленном сервере, поэтому то, что я понял из этой статьи: http://msdn.microsoft.com/en-us/magazine/cc164128.aspx увеличение пула потоков не является выбором, так как это фактически ухудшит производительность (так как я не могу броситьв гору аппаратных средств).

Как вы думаете, что является лучшим решением для моей текущей ситуации?Мне не очень нравится текущий (только из-за интуиции, но в любом случае)

Спасибо за чтение этого ужасно длинного поста ..

Ответы [ 4 ]

2 голосов
/ 01 сентября 2010

Интересно. До вашего вопроса я не знал, что VS изменился с Begin / End на Async / Completed при добавлении веб-ссылок. Я предполагал, что они также будут включать Begin / End, но, видимо, они не включали.

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

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

Вы правы, что Async / Completed заблокирует асинхронную страницу. (примечание: я верю , что они будут не заблокировать синхронную страницу - но я никогда не пробовал этого - так что если вы используете не асинхронную страницу, то вы могли бы Попробуй это). Метод, которым они «блокируют» асинхронную страницу, обернут в SynchronizationContext; в частности, каждая асинхронная страница имеет счетчик ожидающих операций, который увеличивается на Async и уменьшается после Completed.

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

var oldSyncContext = SynchronizationContext.Current;
try
{
  SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
  var serviceName = new ServiceName(..);
  // Note: MyMethodCompleted will be invoked in a ThreadPool thread
  //  but WITHOUT an associated ASP.NET page, so some global state
  //  might be missing. Be careful with what code goes in there...
  serviceName.MethodCompleted += MyMethodCompleted;
  serviceName.MethodAsync(..);
}
finally
{
  SynchronizationContext.SetSynchronizationContext(oldSyncContext);
}

Я написал класс, который обрабатывает временную замену SynchronizationContext.Current как часть библиотеки Nito.Async . Использование этого класса упрощает код до:

using (new ScopedSynchronizationContext(new SynchronizationContext()))
{
  var serviceName = new ServiceName(..);
  // Note: MyMethodCompleted will be invoked in a ThreadPool thread
  //  but WITHOUT an associated ASP.NET page, so some global state
  //  might be missing. Be careful with what code goes in there...
  serviceName.MethodCompleted += MyMethodCompleted;
  serviceName.MethodAsync(..);
}

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

1 голос
/ 01 сентября 2010

попробуйте использовать следующие настройки

[WebMethod]
[SoapDocumentMethod(OneWay = true)]
void MyAsyncMethod(parameters)
{
}

в вашем веб-сервисе

но будьте осторожны, если вы используете олицетворение, у нас были проблемы на нашей стороне.

1 голос
/ 31 августа 2010

Вы можете сделать это:

var action = new Action(CreateService);
action.BeginInvoke(action.EndInvoke, action);

или использовать ThreadPool.QueueUserWorkItem.

При использовании Thread обязательно установите IsBackground=true.

В http://consultingblogs.emc.com/jonathangeorge/archive/2009/09/10/make-methods-fire-and-forget-with-postsharp.aspx

есть отличный пост о пожаре и забывай темы.
0 голосов
/ 01 сентября 2010

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

Подумайте над тем, чтобы сделать более индивидуализированный и оптимизированный подход с использованием платформы MVC. Ваш поток данных может выглядеть так:

  1. Попросите, чтобы исходный запрос к вашей веб-странице породил поток, который гаснет и согревает ваши данные.
  2. Верните клиенту страницу "скелет"
  3. На указанной странице есть ветка javascript, которая вызывает ваш сервер и запрашивает данные.
  4. Используя MVC, создайте действие контроллера, которое возвращает частичное представление, ограниченное только интересующим вас элементом управления.

Это уменьшит нагрузку на ваш сервер (может иметь алгоритм отката), уменьшит объем информации, передаваемой по проводам, и все же даст клиенту большой опыт.

...