总结:这甚至可能吗?
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线程的堆栈展开之前永远不会调用响应回调,并转到某个ui线程函数来抽取堆栈。
全文:
我正在移植一个需要从各种来源创建流的应用程序,其中一个来自简单的http网址。我在后台线程上这样做,理想情况下我希望它100%同步,只需在需要时阻塞(这是好的,因为它在后台线程上)。
但似乎框架有点米老鼠,它假设你将在ui线程上执行请求,因此它将保护编码器不必创建后台线程来执行异步操作。但我可能会遗漏一些东西。
我偶然发现了以下文章: http://pieterderycke.wordpress.com/2011/05/23/adding-synchronous-methods-to-webrequest-on-windows-phone-7/, 这提出了使http web请求同步的解决方案。但是当它实现时,我得到一个ProtocolViolationException。我已经修改了代码以使用BeginGetResponse()而不是BeginGetRequestStream(),这似乎不再导致异常。
但似乎后台线程现在无限期地阻塞。在我的ui线程上,我循环,执行Thread.Sleep(10)因为我在单元测试函数中,等待我的回调被调用。是否有可能在单元测试函数返回并且ui线程有机会抽取消息之前不会调用回调?如果是这样,我可以用任何方式强制它进行泵送,这样我可以继续在单元测试程序中停止的地方吗?
在上面提到的文章的底部,发表评论“如果你测试你的代码,你会发现如果你在UI线程上执行它会死锁。”但是我在后台线程上执行它,所以应该没问题呢?
msdn docs只显示如何进行异步调用。他们还提到“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 :(得分:3)
由于HTTP响应处理使用UI线程,阻止它将阻止请求完成。
假设您使用的是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了解如何在使用SL测试框架时使基于Rx的异步测试更清晰。
答案 1 :(得分:2)
虽然我不主张将内容移动到UI线程,这可能是你最终会遇到的,但有时将同步代码移植到手机上会是很高兴有GetResponse的同步版本。对于我维护的与多个平台兼容的库,I wrote these extensions methods。
答案 2 :(得分:1)
为什么要问错误解决问题?如果需要继续异步请求,则只需使用任务并行库。
您可以在NuGet上找到适用于Windows Phone的TPL版本:Task Parallel Library for Silverlight。
这允许继续,这基本上会产生与阻止你的线程相同的效果。
(Robert McLaws,图书馆的创建者)NuGet是一个可以轻松管理依赖关系的系统。只需转到http://nuget.org/,单击链接进行安装,然后打开包管理器控制台并键入“Install-Package System.Threading.Tasks”,它将自动为您的项目安装正确的版本。我目前没有提供源代码,但我可能会在将来的某个时间。我需要向Mono人员查询,因为代码主要来自Mono。
答案 3 :(得分:1)
您也可以使用Rx(随库提供)来执行此操作。
http://dotnet.dzone.com/articles/5-minute-sample-fromasyncpattern