场景:我想使用 WebBrowser 控件来代理外部网站上的网站导航,以进行研究项目。因此,我尝试使用 WebBrowser 控件在页面请求中加载站点并转发接收到的 HTML 并进行一些修改(如更改 src/href 和 javascript 事件处理程序)。当参与者/用户在代理网站上触发 onclick 事件时,我会在服务器上获取此事件并希望在我的 WebBrowser 控件中重新触发它。
问题:我不知道如何处理 WebBrowser 控件。最初我认为这只是将其存储为会话对象的问题,但它必须在 STA 线程中运行这一事实使这变得困难。当用户调用 onclick 事件以允许我在控件上代理此 onclick 时,我需要相同的活动浏览器对象。现在我使用包装类 IEBrowser:System.Windows.Forms.ApplicationContext。我从不同的来源复制了代码,主要来自(http://www.codeproject.com/Articles/50544/Using-the-WebBrowser-Control-in-ASP-NET),但它不考虑使用相同的 WebBrowser Control over许多请求。以下是 IEBrowser 类的一些代码:
public void Nav(string url)
{
this.url = url;
this.resultEvent = new AutoResetEvent(false);
htmlResult = null;
ths = new ThreadStart(delegate
{
// create a WebBrowser control
ieBrowser = new WebBrowser();
//Reset Session
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_END_BROWSER_SESSION, IntPtr.Zero, 0);
// set WebBrowser event handls
ieBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(IEBrowser_DocumentCompleted);
//make request
ieBrowser.Navigate(url);
System.Windows.Forms.Application.Run(this);
//remove WebBrowser event handler
ieBrowser.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(IEBrowser_DocumentIsCompleted);
//for now, we keep the webBrowser open
//ieBrowser.Dispose();
});
thrd = new Thread(ths);
thrd.Name = "Thread 2";
thrd.IsBackground = true;
// set thread to STA state before starting
thrd.SetApartmentState(ApartmentState.STA);
thrd.Start();
EventWaitHandle.WaitAll(new AutoResetEvent[] { resultEvent });
thrd.Join();
}
// DocumentCompleted event handle
void IEBrowser_DocumentIsCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (ieBrowser.ReadyState == WebBrowserReadyState.Complete && ieBrowser.IsBusy == false)
{
//Replace or Set IDs on every HTML Element [...]
//...
//
ieBrowser.Stop();
ExitThread();
//Dispose();
resultEvent.Set();
}
}
限制:这与性能无关,我需要远程操作,但只有 1-5 人会同时使用该站点。我知道使用 WebBrowser Control 通常可能不是一个好的解决方案,但在这种情况下,这正是我捕获所有用户导航所需要的。