下面是 C#异步方法的代码,该方法还具有WebClient控件的两个事件的回调处理程序:DownloadProgressChanged和OpenReadCompleted。当我运行代码时,最初它会流向“ await DownloadStringTaskAsync() ”调用并退出。然后我看到DownloadProgressChanged的匿名事件处理程序代码触发,这就是我遇到问题的地方。然后代码流向“ return strRet ”语句,因此该方法的返回值是在方法顶部分配给strRet的初始化值“(none)” ,而不是分配给strRet的网页内容在OpenReadCompleted匿名回调中。
所以我需要等待OpenReadCompleted回调在控制流到 return 语句之前执行,但我不确定如何正确执行此操作。如何更正代码,使其在OpenReadCompleted回调执行之前不会到达“ return strRet ”语句?
/// <summary>
/// This method downloads the contents of a URL to a string. Returns the URL contents
/// as a string if it succeeds, throws an Exception if not.
/// <param name="strUrl">The URL to download.</param>
/// <param name="progress">An IProgress object to report download progress to. May be NULL.</param>
/// <param name="cancelToken">A cancellation token. May be NULL.</param>
/// <param name="iNumSecondsToWait">The number of seconds to wait before cancelling the download. Default is 30 seconds</param>
/// </summary>
/// <remarks>
/// Use "await" with this method wrapped in Task.run() to manage the process asynchronously.
///
/// NOTE: The DownloadProgressChanged() event is raised on the UI
/// thread so it is safe to do UI updates from the IProgress.Report()
/// method.
/// </remarks>
async public static Task<string> URLToString(string strUrl, IProgress<int> progress, CancellationToken cancelToken, int iNumSecondsToWait = 30)
{
// The string to be returned.
string strRet = "(none)";
strUrl = strUrl.Trim();
if (String.IsNullOrWhiteSpace(strUrl))
throw new ArgumentException("(Misc::URLToString) The URL is empty.");
if (iNumSecondsToWait < 1)
throw new ArgumentException("(Misc::URLToString) The number of seconds to wait is less than 1.");
// Asynchronous download. Note, the Silverlight version of WebClient does *not* implement
// IDisposable.
WebClient wc = new WebClient();
// Create a download progress changed handler so we can pass on progress
// reports to the caller if they provided a progress report object.
// This event is raised on the UI thread.
wc.DownloadProgressChanged += (s, e) =>
{
// Do we have a progress report handler?
if (progress != null)
// Yes, call it.
progress.Report(e.ProgressPercentage);
// If we have a cancellation token and the operation was cancelled, then abort the download.
if (cancelToken != null)
cancelToken.ThrowIfCancellationRequested();
}; // wc.DownloadProgressChanged += (s, e) =>
// Use a Lambda expression for the "completed" handler
// that writes the downloaded contents as a string to a file.
wc.OpenReadCompleted += (s, e) =>
{
// If we have a cancellation token and the operation was cancelled, then abort the download.
if (cancelToken != null)
cancelToken.ThrowIfCancellationRequested();
// Return the downloaded file as a string.
strRet = e.Result.ToString();
}; // wc.OpenReadCompleted += (s, e) =>
// Now make the call to download the file and do an asynchronous wait for the result.
await wc.DownloadStringTaskAsync(new Uri(strUrl));
// wc.DownloadStringAsync(new Uri(strUrl));
return strRet;
} // async public static void URLToStr
=================================
更新:根据我收到的答案,我已将代码修改为以下内容:
async public static Task<string> URLToStringAsync(string strUrl, IProgress<int> progress, CancellationToken cancelToken, int iNumSecondsToWait = 30)
{
strUrl = strUrl.Trim();
if (String.IsNullOrWhiteSpace(strUrl))
throw new ArgumentException("(Misc::URLToStringAsync) The URL is empty.");
if (iNumSecondsToWait < 1)
throw new ArgumentException("(Misc::URLToStringAsync) The number of seconds to wait is less than 1.");
// Asynchronous download. Note, the Silverlight version of WebClient does *not* implement
// IDisposable.
WebClient wc = new WebClient();
// Create a download progress changed handler so we can pass on progress
// reports to the caller if they provided a progress report object.
// This event is raised on the UI thread.
wc.DownloadProgressChanged += (s, e) =>
{
// Do we have a progress report handler?
if (progress != null)
// Yes, call it.
progress.Report(e.ProgressPercentage);
// If we have a cancellation token and the operation was cancelled, then abort the download.
if (safeCancellationCheck(cancelToken))
wc.CancelAsync();
}; // wc.DownloadProgressChanged += (s, e) =>
// Now make the call to download the file and do an asynchronous wait for the result.
return await wc.DownloadStringTaskAsync(new Uri(strUrl));
} // async public static void URLToStringAsync