2011-09-04 3 views
6

Резюме: Возможно ли это?Как я могу заставить HttpWebRequest вести себя как можно синхронно?

unit test function on ui thread: 
- creates a background thread 
- starts the thread 
- waits for it to complete (function does not exit until it completes!) 

background thread: 
- opens an http stream 
- reads a url from the web 
- terminates 

Мое подозрение: Структура асинхронно помещает результат на некоторую внутреннюю очередь сообщений и, таким образом, обратный вызов ответа никогда не будет называться, пока стек Ui потока не раскручивается и идет к некоторой функции щ нить накачать стек.


Полная история:

Я портирование приложения, которое требует создание потока из различных источников, одна из которых с помощью простого HTTP URL. Я делаю это в фоновом потоке, и в идеале я бы хотел, чтобы он действовал на 100% синхронно, просто блокируйте при необходимости (это нормально, так как он находится в фоновом потоке).

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

Я наткнулся на следующую статью: http://pieterderycke.wordpress.com/2011/05/23/adding-synchronous-methods-to-webrequest-on-windows-phone-7/, , которая предлагает решение для синхронного использования веб-запроса http. Но поскольку это реализовано, я получаю исключение ProtocolViolationException. С тех пор я сделал модификацию кода для использования BeginGetResponse() вместо BeginGetRequestStream(), и это, похоже, больше не вызывает исключение.

Но кажется, что фоновый поток теперь блокируется бесконечно. В моем потоке ui я петлю, делая Thread.Sleep (10), так как я нахожусь в модульной тестовой функции, ожидая, когда мой callback будет вызван. Возможно ли, что обратный вызов не будет вызываться до тех пор, пока функция тестирования единицы не вернется, и нить ui не сможет перекачать сообщения? Если да, то каким-либо образом я могу заставить его перекачивать, чтобы я мог продолжить, где я остановился в процедуре тестирования устройства?

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

В документах msdn показано только, как выполнять асинхронные вызовы. И они также отмечают, что «Метод BeginGetResponse требует выполнения некоторых задач синхронной настройки« ... », как правило, несколько секунд« ... но »может занимать 60 секунд или более». Это звучит довольно плохо, чтобы исполняться на нити ui. http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse.aspx

Пожалуйста, помогите!

Вот мой код:

using System.Net; 
using System.Threading; 
using System; 
using System.IO; 

namespace Blah 
{ 
    // http://pieterderycke.wordpress.com/2011/05/23/adding-synchronous-methods-to-webrequest-on-windows-phone-7/ 
    // Creates synchronous web requests. 
    // Must not be called on UI threads. 

    public static class WebRequestExtensions 
    { 
    public static Stream GetRequestStream(this WebRequest request) 
    { 
     AutoResetEvent autoResetEvent = new AutoResetEvent(false); 

     IAsyncResult asyncResult = null; 
     { 
     // http://stackoverflow.com/questions/253549/how-do-i-use-httpwebrequest-with-get-method 

     if (request.Method == "GET") 
     { 
      asyncResult = request.BeginGetResponse(
      r => autoResetEvent.Set(), null); 
     } 
     else 
     { 
      asyncResult = request.BeginGetRequestStream(
      r => autoResetEvent.Set(), null); 
     } 
     } 

     // Wait until the call is finished 
     autoResetEvent.WaitOne(); 

     return request.EndGetRequestStream(asyncResult); 
    } 
    } 
} 

Я недавно наткнулся на http://www.eggheadcafe.com/tutorials/aspnet/91f69224-3da5-4959-9901-c5c717c9b184/making-silverlight-emulate-synchronous-requests.aspx, но это показывает ту же проблему. Кажется, что я не получаю свой обратный вызов, пока нить ui не вернет стек ... Я где-то чувствую запах какой-то очереди сообщений фрейма, правильно ли я прав?

Благодарности

+0

Код выглядит хорошо для меня. Я думаю, что ProtocolViolationException вам что-то говорит! Какой URL-адрес вы используете? что было полным сообщением об исключении? – ColinE

+0

Спасибо, но, как я уже сказал, ProtocolViolationException ушел, поскольку я заменил request.BeginGetRequestStream() на request.BeginGetResponse(). – swinefeaster

ответ

3

При обработке ответа HTTP использует поток пользовательского интерфейса, блокируя это предотвратит запрос от завершения.

Предполагая, что вы используете Silverlight Unit Testing Framework биты, вы можете пометить свой тест как [Asynchronous]:

using System; 
using System.Net; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using Microsoft.Silverlight.Testing; 

[TestClass] 
public class WebRequestsTests : WorkItemTest 
{ 
    [TestMethod, Asynchronous] 
    public void TestWebRequest() 
    { 
     var webRequest = WebRequest.CreateHttp("http://www.stackoverflow.com"); 

     webRequest.BeginGetResponse(result => 
     { 
      EnqueueCallback(() => 
      { 
       WebResponse response = webRequest.EndGetResponse(result); 

       // process response 

       TestComplete(); // async test complete 
      }); 
     }, null); 
    } 
} 

В качестве альтернативы, если вы хотите использовать Rx (который я, лично), я недавно did a blog post о том, как сделать асинхронные тесты на основе Rx более чистыми при использовании платформы тестирования SL.

+0

@swinefeaster - Первая строка моего ответа - это прямой ответ на ваш вопрос (что это невозможно и почему). –

+0

Интересно, это может сработать, но мне нужно будет обобщить это решение для работы с моим движком. Я использую тестовую среду с http://www.jeff.wilcox.name/2011/06/updated-ut-mango-bits/, а тэг [Asynchronous], похоже, не поддерживается (я получаю компилятор ошибка). – swinefeaster

+0

@swinefeaster - это действительно часть фреймворка, но она находится в пространстве имен Microsoft.Silverlight.Testing. –

1

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

Вы можете найти версию TPL для Windows Phone на NuGet: Task Parallel Library for Silverlight.

Это позволяет продолжить, что существенно пойдет на то, чтобы блокировать поток.

(Robert McLaws, создатель библиотеки) NuGet - это система, которая упрощает управление зависимостями. Просто зайдите в http://nuget.org/, щелкните по ссылке, чтобы установить его, затем откройте консоль диспетчера пакетов и введите «Install-Package System.Threading.Tasks», и он автоматически установит правильную версию для вашего проекта. В настоящее время я не делаю источник доступным, хотя я мог бы когда-нибудь в будущем. Мне нужно проверить с ребятами из Mono, так как код приходит в основном из Mono.

+0

Я не вижу ссылку для скачивания там, где есть исходные файлы ...? – swinefeaster

+0

Роберт добавил свой комментарий в редактировании моего сообщения (так как он как-то не мог написать его как комментарий) –

+0

Можете ли вы показать пример того, как я могу использовать эту библиотеку для синхронного получения содержимого веб-страницы и возврата ее содержимого как строка? Спасибо – swinefeaster

1

Вы также можете использовать Rx (который поставляется с библиотекой) для этого.

http://dotnet.dzone.com/articles/5-minute-sample-fromasyncpattern

+0

Выполняет ли это вызовы синхронизации из асинхронных вызовов? На первый взгляд кажется, что он просто помогает с синтаксисом, но под ним все еще выполняется async ... – swinefeaster

+0

Да, но, как и в TPL, Rx использует продолжения, то есть вы можете просто выполнить код, когда запрос (async) будет выполнен, а не чтобы заблокировать поток. –

+0

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

2

В то время как я не, защищающий перемещение материала к потоку пользовательского интерфейса, на что вы, вероятно, собираетесь закончиться, бывают случаи, когда вы портируете синхронный код на телефон, что было бы неплохо иметь синхронная версия GetResponse. I wrote these extensions methods для библиотеки, которую я поддерживаю, совместим с несколькими платформами.

Смежные вопросы