C# 如何在超时后取消任务等待
我使用此方法以编程方式实例化web浏览器,导航到url,并在文档完成后返回结果 如果加载文档的时间超过5秒,我如何停止C# 如何在超时后取消任务等待,c#,.net,webbrowser-control,task-parallel-library,console-application,C#,.net,Webbrowser Control,Task Parallel Library,Console Application,我使用此方法以编程方式实例化web浏览器,导航到url,并在文档完成后返回结果 如果加载文档的时间超过5秒,我如何停止任务并让GetFinalUrl()返回null 我见过许多使用TaskFactory的示例,但我无法将其应用于此代码 private Uri GetFinalUrl(PortalMerchant portalMerchant) { SetBrowserFeatureControl(); Uri finalUri = null;
任务
并让GetFinalUrl()
返回null
我见过许多使用TaskFactory
的示例,但我无法将其应用于此代码
private Uri GetFinalUrl(PortalMerchant portalMerchant)
{
SetBrowserFeatureControl();
Uri finalUri = null;
if (string.IsNullOrEmpty(portalMerchant.Url))
{
return null;
}
Uri trackingUrl = new Uri(portalMerchant.Url);
var task = MessageLoopWorker.Run(DoWorkAsync, trackingUrl);
task.Wait();
if (!String.IsNullOrEmpty(task.Result.ToString()))
{
return new Uri(task.Result.ToString());
}
else
{
throw new Exception("Parsing Failed");
}
}
// by Noseratio - http://stackoverflow.com/users/1768303/noseratio
static async Task<object> DoWorkAsync(object[] args)
{
_threadCount++;
Console.WriteLine("Thread count:" + _threadCount);
Uri retVal = null;
var wb = new WebBrowser();
wb.ScriptErrorsSuppressed = true;
TaskCompletionSource<bool> tcs = null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) => tcs.TrySetResult(true);
foreach (var url in args)
{
tcs = new TaskCompletionSource<bool>();
wb.DocumentCompleted += documentCompletedHandler;
try
{
wb.Navigate(url.ToString());
await tcs.Task;
}
finally
{
wb.DocumentCompleted -= documentCompletedHandler;
}
retVal = wb.Url;
wb.Dispose();
return retVal;
}
return null;
}
public static class MessageLoopWorker
{
#region Public static methods
public static async Task<object> Run(Func<object[], Task<object>> worker, params object[] args)
{
var tcs = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
EventHandler idleHandler = null;
idleHandler = async (s, e) =>
{
// handle Application.Idle just once
Application.Idle -= idleHandler;
// return to the message loop
await Task.Yield();
// and continue asynchronously
// propogate the result or exception
try
{
var result = await worker(args);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
// signal to exit the message loop
// Application.Run will exit at this point
Application.ExitThread();
};
// handle Application.Idle just once
// to make sure we're inside the message loop
// and SynchronizationContext has been correctly installed
Application.Idle += idleHandler;
Application.Run();
});
// set STA model for the new thread
thread.SetApartmentState(ApartmentState.STA);
// start the thread and await for the task
thread.Start();
try
{
return await tcs.Task;
}
finally
{
thread.Join();
}
}
#endregion
}
private Uri GetFinalUrl(PortalMerchant PortalMerchant)
{
SetBrowserFeatureControl();
Uri finalUri=null;
if(string.IsNullOrEmpty(portalMethant.Url))
{
返回null;
}
uritrackingurl=新的Uri(portalMerchant.Url);
var task=MessageLoopWorker.Run(DoWorkAsync,trackingUrl);
task.Wait();
如果(!String.IsNullOrEmpty(task.Result.ToString()))
{
返回新Uri(task.Result.ToString());
}
其他的
{
抛出新异常(“解析失败”);
}
}
//按比例—http://stackoverflow.com/users/1768303/noseratio
静态异步任务DoWorkAsync(对象[]args)
{
_threadCount++;
Console.WriteLine(“线程计数:”+_线程计数);
uriretval=null;
var wb=新的WebBrowser();
wb.ScriptErrorsSuppressed=true;
TaskCompletionSource tcs=null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler=(s,e)=>tcs.TrySetResult(true);
foreach(参数中的变量url)
{
tcs=新任务完成源();
wb.DocumentCompleted+=documentCompletedHandler;
尝试
{
导航(url.ToString());
等待tcs任务;
}
最后
{
wb.DocumentCompleted-=documentCompletedHandler;
}
retVal=wb.Url;
wb.Dispose();
返回返回;
}
返回null;
}
公共静态类MessageLoopWorker
{
#区域公共静态方法
公共静态异步任务运行(Func worker,params object[]args)
{
var tcs=new TaskCompletionSource();
变量线程=新线程(()=>
{
EventHandler idleHandler=null;
idleHandler=async(s,e)=>
{
//处理应用程序。仅空闲一次
Application.Idle-=idleHandler;
//返回到消息循环
等待任务;
//并异步继续
//提出结果或例外
尝试
{
var结果=等待工作人员(args);
tcs.SetResult(结果);
}
捕获(例外情况除外)
{
tcs.SetException(ex);
}
//退出消息循环的信号
//此时将退出Application.Run
Application.ExitThread();
};
//处理应用程序。仅空闲一次
//确保我们在消息循环中
//和SynchronizationContext已正确安装
Application.Idle+=idleHandler;
Application.Run();
});
//为新线程设置STA模型
SetApartmentState(ApartmentState.STA);
//启动线程并等待任务
thread.Start();
尝试
{
返回等待任务;
}
最后
{
thread.Join();
}
}
#端区
}
我怀疑在另一个线程上运行处理循环不会很好,因为WebBrowser
是承载ActiveX控件的UI组件
在编写时,我建议您使用扩展方法保持代码整洁:
public static Task<string> NavigateAsync(this WebBrowser @this, string url)
{
var tcs = new TaskCompletionSource<string>();
WebBrowserDocumentCompletedEventHandler subscription = null;
subscription = (_, args) =>
{
@this.DocumentCompleted -= subscription;
tcs.TrySetResult(args.Url.ToString());
};
@this.DocumentCompleted += subscription;
@this.Navigate(url);
return tcs.Task;
}
公共静态任务NavigateAsync(此WebBrowser@this,字符串url)
{
var tcs=new TaskCompletionSource();
WebBrowserDocumentCompletedEventHandler订阅=null;
订阅=(\ux,args)=>
{
@this.DocumentCompleted-=订阅;
TrySetResult(args.Url.ToString());
};
@this.DocumentCompleted+=订阅;
@这个.导航(url);
返回tcs.Task;
}
现在,您的代码可以轻松应用超时:
async Task<string> GetUrlAsync(string url)
{
using (var wb = new WebBrowser())
{
var navigate = wb.NavigateAsync(url);
var timeout = Task.Delay(TimeSpan.FromSeconds(5));
var completed = await Task.WhenAny(navigate, timeout);
if (completed == navigate)
return await navigate;
return null;
}
}
异步任务GetUrlAsync(字符串url)
{
使用(var wb=new WebBrowser())
{
var navigate=wb.NavigateAsync(url);
var timeout=任务延迟(TimeSpan.FromSeconds(5));
var completed=等待任务.wheny(导航,超时);
如果(已完成==导航)
返回等待导航;
返回null;
}
}
可按如下方式使用:
private async Task<Uri> GetFinalUrlAsync(PortalMerchant portalMerchant)
{
SetBrowserFeatureControl();
if (string.IsNullOrEmpty(portalMerchant.Url))
return null;
var result = await GetUrlAsync(portalMerchant.Url);
if (!String.IsNullOrEmpty(result))
return new Uri(result);
throw new Exception("Parsing Failed");
}
private异步任务GetFinalUrlAsync(PortalMethant PortalMethant)
{
SetBrowserFeatureControl();
if(string.IsNullOrEmpty(portalMethant.Url))
返回null;
var result=await GetUrlAsync(portalMerchant.Url);
如果(!String.IsNullOrEmpty(结果))
返回新的Uri(结果);
抛出新异常(“解析失败”);
}
更新:基于WebBrowser
的控制台web刮板的最新版本可以下载
已更新:用于多个并行下载
你有没有关于如何在控制台应用程序中通过任何
机会?我也不认为webBrowser是一个类变量,因为
我以并行方式运行整个过程,每次迭代
数千个网址
下面是一个或多或少通用的**WebBrowser
-基于web的scraper**的实现,它作为控制台应用程序工作。这是对我以前的一些WebBrowser
相关工作的整合,包括问题中引用的代码:
- 可重用的
类用于启动和运行带有自己消息泵的WinForms STA线程。信息技术messageloopfamilt
public static Task<string> NavigateAsync(this WebBrowser @this, string url) { var tcs = new TaskCompletionSource<string>(); WebBrowserDocumentCompletedEventHandler subscription = null; subscription = (_, args) => { @this.DocumentCompleted -= subscription; tcs.TrySetResult(args.Url.ToString()); }; @this.DocumentCompleted += subscription; @this.Navigate(url); return tcs.Task; }
public static async Task<string> NavAjaxAsync(this WebBrowser @this) { // get the root element var documentElement = @this.Document.GetElementsByTagName("html")[0]; // poll the current HTML for changes asynchronosly var html = documentElement.OuterHtml; while (true) { // wait asynchronously await Task.Delay(POLL_DELAY); // continue polling if the WebBrowser is still busy if (webBrowser.IsBusy) continue; var htmlNow = documentElement.OuterHtml; if (html == htmlNow) break; // no changes detected, end the poll loop html = htmlNow; } return @this.Document.Url.ToString(); }
public static async Task NavAndAjaxAsync(this WebBrowser @this, string url) { await @this.NavigateAsync(url); await @this.NavAjaxAsync(); }
async Task<string> GetUrlAsync(string url) { using (var wb = new WebBrowser()) { var navigate = wb.NavAndAjaxAsync(url); var timeout = Task.Delay(TimeSpan.FromSeconds(5)); var completed = await Task.WhenAny(navigate, timeout); if (completed == navigate) return await navigate; return null; } }