Silverlight 不支持同步的 Web 请求。因此,我编写了 简单异步操作运行器。其中一个目标是能够像同步代码一样编写代码,然后修改它以与运行器代码一起使用。
首先,从第一部分中获取 AsyncOperationService
的小段代码,并将其添加到您的项目中(如果您觉得这篇文章有些沉重,不用担心,这对于实际使用不重要)。
使用您提供的代码作为“同步模板”,我们可以看到我们需要一些 AsyncOperation
的实现来处理 GetRequestStream
和 GetResponseStream
,因此我们将编写它们并将它们添加到项目中:
public static class WebRequestAsyncOps
{
public static AsyncOperation GetRequestStreamOp(this WebRequest request, Action<Stream> returnResult)
{
return (completed) =>
{
request.BeginGetRequestStream((result) =>
{
try
{
returnResult(request.EndGetRequestStream(result));
completed(null);
}
catch (Exception err)
{
completed(err);
}
}, null);
};
}
public static AsyncOperation GetResponseOp(this WebRequest request, Action<WebResponse> returnResult)
{
return (completed) =>
{
request.BeginGetResponse((result) =>
{
try
{
returnResult(request.EndGetResponse(result));
completed(null);
}
catch (Exception err)
{
completed(err);
}
}, null);
};
}
}
如果你正在分块上传文件,那么你可能希望将进度报告到用户界面中。我建议你在手头上准备好这个AsyncOperation
(注入到现有的AsyncOperationService
类中):
public static AsyncOperation SwitchToUIThread()
{
return (completed => Deployment.Current.Dispatcher.BeginInvoke(() => completed(null)));
}
现在我们可以创建您的代码的异步版本:-
IEnumerable<AsyncOperation> Chunker(Action<double> reportProgress)
{
double progress = 0.0;
Chunk chunk = new Chunk();
while (chunk != null)
{
Stream outStream = null;
HttpWebRequest req = ...
yield return req.GetRequestStreamOp(s => outStream = s);
WebResponse response = null;
yield return req.GetResponseOp(r => response = r);
yield return AsyncOperationService.SwitchToUIThread();
reportProgress(progress);
chunk = null;
if (moreNeeded)
{
chunk = new Chunk();
}
}
}
最后,你只需要运行它并处理任何错误:-
Chunker.Run((err) =>
{
if (err == null)
{
}
else
{
}
});