Silverlight不支持同步Web請求。爲此,我寫了Simple Asynchronous Operation Runner。其中一個目標是能夠編寫代碼,就好像它是同步的,然後修改它以使用runner代碼。
首先從第1部分獲得AsyncOperationService
的小塊代碼,並將其添加到項目中(如果發現文章有點過重,那麼實際使用它並不重要)。
使用你已經爲「同步模板」所提供的代碼,我們可以看到,我們需要GetRequestStream
和GetResponseStream
幾個AsyncOperation
實現,所以我們寫的那些它們添加到項目,以及: -
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);
};
}
}
現在,如果你是分塊上傳一個文件,你可能會想報告進展到UI所以我建議你有這個AsyncOperation
手頭以及(在注入到現有AsyncOperationService類): -
public static AsyncOperation SwitchToUIThread()
{
return (completed => Deployment.Current.Dispatcher.BeginInvoke(() => completed(null)));
}
現在我們可以creare代碼的異步版本: -
IEnumerable<AsyncOperation> Chunker(Action<double> reportProgress)
{
double progress = 0.0;
Chunk chunk = new Chunk();
// Setup first chunk;
while (chunk != null)
{
Stream outStream = null;
HttpWebRequest req = ...
yield return req.GetRequestStreamOp(s => outStream = s);
// Do stuff to and then close outStream
WebResponse response = null;
yield return req.GetResponseOp(r => response = r);
// Do stuff with response throw error is need be.
// Increment progress value as necessary.
yield return AsyncOperationService.SwitchToUIThread();
reportProgress(progress);
chunk = null;
if (moreNeeded)
{
chunk = new Chunk();
// Set up next chunk;
}
}
}
最後你只需要運行它,並處理任何錯誤: -
Chunker.Run((err) =>
{
if (err == null)
{
// We're done
}
else
{
// Oops something bad happened.
}
});