试图绕过TaskCompletionSource
。这是我写的同步(WebBrowser.Navigate()
异步)下载网页并将其返回给调用者的小课程。我不确定我是否正确使用了TaskCompletionSource
。有人可以说明我在这里缺少什么,或者这完全是一个过度设计的解决方案吗?
class PageDownloader
{
private WebBrowser _WB = new WebBrowser();
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public PageDownloader()
{
_WB.LoadCompleted += _WB_LoadCompleted;
}
public string Download(string url)
{
_WB.Navigate(new Uri(url));
tcs.Task.Wait();
if (tcs.Task.IsCanceled || tcs.Task.IsFaulted)
return null;
else
return (_WB.Document as mshtml.HTMLDocument).body.innerHTML;
}
private void _WB_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
var docTemp = _WB.Document as mshtml.HTMLDocument;
foreach (mshtml.IHTMLImgElement imgElemt in docTemp.images)
imgElemt.src = "";
tcs.SetResult(true);
}
}
答案 0 :(得分:1)
我不确定async
这里的含义,但WebBrowser.Navigate
方法只返回void
,无法使用async
/ await
关键字等待在C#5中引入的。它会启动导航操作并立即返回,如果您想在导航实际完成后执行某些操作,则应订阅LoadCompleted
事件处理程序。到目前为止一切都很好。
使用TaskCompletionSource<T>
您实际上可以在班级Download
中设置async
方法,这样您实际上可以await
结果。您可能还想捕获LoadCompleted
事件处理程序中可能发生的任何异常:
class PageDownloader
{
private WebBrowser _WB = new WebBrowser();
private TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
public PageDownloader()
{
_WB.LoadCompleted += _WB_LoadCompleted;
}
public async Task<string> DownloadAsync(string url)
{
_WB.Navigate(new Uri(url));
await tcs.Task.ConfigureAwait(false);
if (tcs.Task.IsCanceled || tcs.Task.IsFaulted)
return null;
else
return tcs.Task.Result;
}
private void _WB_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
try
{
var docTemp = _WB.Document as mshtml.HTMLDocument;
foreach (mshtml.IHTMLImgElement imgElemt in docTemp.images)
imgElemt.src = "";
tcs.SetResult(docTemp.body.innerHTML);
}
catch(Exception ex)
{
tcs.SetException(ex);
}
}
}
<强>用法:强>
PageDownloader downloader = new PageDownloader();
string html = await downloader.DownloadAsync("http://stackoverflow.com");
//or if you want to block synchronously
string html = downloader.DownloadAsync("http://stackoverflow.com").Result;
您也可以在班级中创建同步重载:
public string Download(string url)
{
return DownloadAsync(url).Result;
}
答案 1 :(得分:0)
到目前为止,唯一有效的解决方案是使用Windows窗体WebBrowser控件,并使用以下代码:
public string Download(string url)
{
bool flag = false;
using (System.Windows.Forms.WebBrowser WB = new System.Windows.Forms.WebBrowser())
{
WB.DocumentCompleted += (sender, e) =>
{
var docTemp = WB.Document;
foreach (HtmlElement imgElemt in docTemp.Images)
imgElemt.SetAttribute("src", "");
flag = true;
};
WB.Navigate(url);
while (!flag)
Application.DoEvents();
return WB.Document.Body.InnerHtml;
}
}
即使我只是在此代码中使用WPF WebBrowser
控件替换WinForms版本,此代码也不会命中return
行。
寻找更好的答案。