c# Web browser keeps freezing but regular IE9 browser does not - c#

I'm using visual studio c# 2010 for the web browser.
WebBrowser 1 navigates to this link:
http://www.costco.com/IOGEAR-Wireless-1080p-HDMI-Transmitter-and-Receiver-3D-Compatible-2x-HDMI-Ports.product.100011675.html
When it reaches the page, it loads and freezes.
I don't think there is something wrong with the web page because chrome, firefox, and the regular IE9 don't freeze at all.
Only the web browser in my c# program freezes when it navigates to this link.
How do I prevent this from freezing? The web page seems to be calling some html data from another site.
I tried adding this code to my program
this.webBrowser1.ScriptErrorsSuppressed = true;
and I also changed the registry values of the web browser so that it will use internet explorer version 9 and so far these two did not work.
this is the code i'm using
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
webBrowser1.ScriptErrorsSuppressed = true;
}
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("http://www.costco.com/IOGEAR-Wireless-1080p-HDMI-Transmitter-and-Receiver-3D-Compatible-2x-HDMI-Ports.product.100011675.html");
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
}
}
}

The issue is not with the WebBrowser control per se, it is with how that particular website is trying to execute some Javascript that gets stuck in a loop.
Compare and contrast:
1) Change the url to http://google.com. Works fine.
2) Now. Add an event handler for the Navigating event. Something like:
this.webBrowser1.Navigating += new System.Windows.Forms.WebBrowserNavigatingEventHandler(this.webBrowser1_Navigating);
and
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
Console.WriteLine("Navigating to: " + e.Url);
}
You will see that there is a JavaScript function that is constantly trying to redirect the page. Here's what shows up in my console output (goes on indefinitely):
Navigating to: javascript:void((function(){document.open();document.domain='costco.com';document.write('<!DOCTYPE html>');document.close();})())
Navigating to: about:blank
Navigating to: javascript:void((function(){document.open();document.domain='costco.com';document.write('<!DOCTYPE html>');document.close();})())
Navigating to: about:blank
Navigating to: javascript:void((function(){document.open();document.domain='costco.com';document.write('<!DOCTYPE html>');document.close();})())
Navigating to: about:blank
Navigating to: javascript:void((function(){document.open();document.domain='costco.com';document.write('<!DOCTYPE html>');document.close();})())
Which makes the webBrowser control essentially unusable.
EDIT:
Ok, one stab at a workaround (this is probably terrible, but it's frustrating that the weird redirect loop is only happening in the WebBrowser control's browser).
If you block the Navigating event from being called before another Navigating event has completed, it loads the page and does not freeze, and the links appear to work. It goes something like this:
private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
Console.WriteLine("Navigated to: " + e.Url);
isNavigating = false;
webBrowser1.AllowNavigation = true;
}
bool isNavigating = false;
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (isNavigating && e.Url.ToString().Contains("javascript:void((function(){document.open();document.domain='costco.com'"))
{
webBrowser1.Stop();
webBrowser1.AllowNavigation = false;
return;
}
isNavigating = true;
Console.WriteLine("Navigating to: " + e.Url);
}

Related

How to use CoreWebView2Frame Class in windows application

I have a windows webview2 application where we are automating 3rd party website with too many nested iframes and I want to execute javascript in a particular iframe. I want to know how get CoreWebView2Frame instance for the particular iframe using WebView2. Microsoft documentation didn't help.
I am looking for an example or a documentation to work with CoreWebView2Frame Class and shows how to execute javascript in a particular iframe by using CoreWebView2Frame.ExecuteAsync().
I have gone throught the this thread but it's too difficult for me to understand.
You can get a CoreWebView2Frame by handling FrameCreated event and use it later.
Example:
In the following example, the WebView2 browses this Uri, then we find the iframe inside the page, and store it for later use. Later when the user clicks on a button on the WinForms app, using ExecuteScriptAsync method of the iframe, we click on a link inside the iframe programmatically.
To do so, drop a WebView2 and a Button on the form. Handle Load event of the form and Click event of the button and modify the code like this:
//using Microsoft.Web.WebView2.Core;
CoreWebView2Frame sampleFrame;
private async void Form1_Load(object sender, EventArgs e)
{
webView21.Source = new Uri(
"https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_link_test");
await webView21.EnsureCoreWebView2Async();
webView21.CoreWebView2.FrameCreated += CoreWebView2_FrameCreated;
}
private void CoreWebView2_FrameCreated(object? sender,
CoreWebView2FrameCreatedEventArgs e)
{
if (e.Frame.Name == "iframeResult")
{
sampleFrame = e.Frame;
}
}
private async void button1_Click(object sender, EventArgs e)
{
if (sampleFrame != null && sampleFrame.IsDestroyed() == 0)
{
await sampleFrame.ExecuteScriptAsync(
"document.getElementsByTagName('a')[0].click();");
}
}
Now if you click on the button, the link which is inside the iframe will be clicked.

Trying to override NavigationMode.Back

I'm trying to develop a simple app for Windows Phone 8, and there are many requirements for the use of the Back Button. As I don't want the Back Button to simply GoBack in back stack, I'd like to pop up a message box to warn the user that this action will bring him back to main menu.
Problem is, this page has to be reloaded some times, and the following code stop working properly after 1 reload. The messagebox opens multiple times. And the more times I reload, the more MessageBox appears.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using BackButtonTests.Resources;
namespace BackButtonTests
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
NavigationService.Navigating += NavigationService_Navigating;
}
void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
{
e.Cancel = true;
MessageBox.Show("Quit");
}
}
private void Restart_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/MainPage.xaml?reload=" + DateTime.Now.ToString(), UriKind.RelativeOrAbsolute));
//Use this fake reload query with unique value as a way to "deceive" the system, as windowsphone does not support NavigationService.Reload, and using simply the Uri of the same page will not properly load everything
}
private void Quit_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Quit");
}
}
}
This is just a test code I wrote, that shows exactly the problem I'm experiencing in my actual project. Of course there are 2 buttons written in xaml.
And the code won't work until you first reload the page, as it's not NavigatedTo when it's the front page (not a problem in my actual project).
Any clues of what I'm doing wrong?
NOTE: I'm not interested in changing the event handler (to OnBackKeyPress, for instance). I'm interested in understanding what's going on with the handler I chose (NavigationService.Navigating, NavigationMode.Back). Thanks
Updated following additional information that clarifies the questing
Changing your navigating event handler to will mean the event isn't fired on every page in the stack
void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
NavigationService.Navigating -= NavigationService_Navigating;
if (e.NavigationMode == NavigationMode.Back)
{
e.Cancel = true;
MessageBox.Show("Quit");
}
}
No longer neccessary
Override OnBackKeypress instead of navigating
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
var DoYouWantToQuit = MessageBox.Show("Are you sure you want to Quit", "Quit", MessageBoxButtons.OkCancel);
if (DoYouWantToQuit != MessageBoxButton.Ok)
{
e.Cancel = true
}
base.OnBackKeyPress(e);
}

simulate click button after opening webpage

I have a requirement where I open a webpage using
WebRequest wr = WebRequest.Create(uri);
This webpage has a download button which needs to be clicked to download a zip file to my local directory. I do not know the URL for this download button, if i mouse over it it just shows the .aspx address.
Now how can I simulate this click so I can download the file?
using System;
using System.Windows.Forms;
namespace SampleBrowserautomate
{
public partial class Form1 : Form
{
// first of all, insert web browser control and button control into your form
string target = "https://www.facebook.com/login.php";
public Form1()
{
InitializeComponent();
}
private void btnGo_Click(object sender, EventArgs e)
{
webBrowser1.Navigate(target);
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser b = (WebBrowser)sender;
b.Document.GetElementById("email").InnerText = "helloworld#gmail.com";
b.Document.GetElementById("pass").InnerText = "HelloWorld";
b.Document.GetElementById("u_0_1").InvokeMember("click");
}
}
}
Another examples on msdn
http://msdn.microsoft.com/en-us/library/System.Windows.Forms.HtmlElement(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.htmlelement.setattribute(v=vs.110).aspx
What about UI automation? Is this what you're after?
http://msdn.microsoft.com/en-us/library/dd286726.aspx
EDIT: How about Web UI automation?
http://msdn.microsoft.com/en-us/library/hh404082.aspx
So I am working on this in between things, but check this out.
You can fire the client side event of that button using this javascript:
__doPostBack('DownloadButton','OnClick');
This will work with the 'javascript:' header in the chrome console. Now you could probably automate this using greasemonkey(firefox) or another add on for chrome.

How to detect crashing tabed webbrowser and handle it?

I have a desktop application (forms) with a tab control, I assign a tab and a new custom webrowser control. I open up about 10 of these tabs. Each one visits about 100 - 500 different pages.
The trouble is that if 1 webbrowser control has a problem it shuts down the entire program.
I want to be able to close the offending webbrowser control and open a new one in it's place.
Is there any event that I need to subscribe to catch a crashing or unresponsive webbrowser control ?
I am using C# on windows 7 (Forms), .NET framework v4
===============================================================
UPDATE: 1 - The Tabbed WebBrowser Example
Here is the code I have and How I use the webbrowser control in the most basic way.
Create a new forms project and name it SimpleWeb
Add a new class and name it myWeb.cs, here is the code to use.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Policy;
namespace SimpleWeb
{
//inhert all of webbrowser
class myWeb : WebBrowser
{
public myWeb()
{
//no javascript errors
this.ScriptErrorsSuppressed = true;
//Something we want set?
AssignEvents();
}
//keep near the top
private void AssignEvents()
{
//assign WebBrowser events to our custom methods
Navigated += myWeb_Navigated;
DocumentCompleted += myWeb_DocumentCompleted;
Navigating += myWeb_Navigating;
NewWindow += myWeb_NewWindow;
}
#region Events
//List of events:http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser_events%28v=vs.100%29.aspx
//Fired when a new windows opens
private void myWeb_NewWindow(object sender, System.ComponentModel.CancelEventArgs e)
{
//cancel all popup windows
e.Cancel = true;
//beep to let you know canceled new window
Console.Beep(9000, 200);
}
//Fired before page is navigated (not sure if its before or during?)
private void myWeb_Navigating(object sender, System.Windows.Forms.WebBrowserNavigatingEventArgs args)
{
}
//Fired after page is navigated (but not loaded)
private void myWeb_Navigated(object sender, System.Windows.Forms.WebBrowserNavigatedEventArgs args)
{
}
//Fired after page is loaded (Catch 22 - Iframes could be considered a page, can fire more than once. Ads are good examples)
private void myWeb_DocumentCompleted(System.Object sender, System.Windows.Forms.WebBrowserDocumentCompletedEventArgs args)
{
}
#endregion
//Answer supplied by mo. (modified)?
public void OpenUrl(string url)
{
try
{
//this.OpenUrl(url);
this.Navigate(url);
}
catch (Exception ex)
{
MessageBox.Show("Your App Crashed! Because = " + ex.ToString());
//MyApplication.HandleException(ex);
}
}
//Keep near the bottom
private void RemoveEvents()
{
//Remove Events
Navigated -= myWeb_Navigated;
DocumentCompleted -= myWeb_DocumentCompleted;
Navigating -= myWeb_Navigating;
NewWindow -= myWeb_NewWindow;
}
}
}
On Form1 drag a standard tabControl and set the dock to fill, you can go into the tab collection and delete the pre-populated tabs if you like.
Right Click on Form1 and Select "View Code" and replace it with this code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using mshtml;
namespace SimpleWeb
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Load Up 10 Tabs
for (int i = 0; i <= 10; i++)
{
newTab("Test_" + i, "http://wwww.yahoo.com");
}
}
private void newTab(string Title, String Url)
{
//Create a new Tab
TabPage newTab = new TabPage();
newTab.Name = Title;
newTab.Text = Title;
//create webbrowser Instance
myWeb newWeb = new myWeb();
//Add webbrowser to new tab
newTab.Controls.Add(newWeb);
newWeb.Dock = DockStyle.Fill;
//Add New Tab to Tab Pages
tabControl1.TabPages.Add(newTab);
newWeb.OpenUrl(Url);
}
}
}
Save and Run the project.
Using the answer below by mo. , you can surf the first url with no problem, but what about all the urls the user clicks on? How do we check those?
I prefer not to add events to every single html element on a page, there has to be a way to run the new urls thru the function OpenUrl before it navigates without having an endless loop.
Thanks.
You can use the AppDomain.UnhandledException or Application.ThreadException event.
But handling exceptions this way may end up in having an invalid state in your application.
Could you describe, when these exceptions occur.
Are they a result of executing a method?
Then it is much better to handle the error in the calling method.
void OpenUrl(Url url)
{
try
{
var webBrowser = GetWebBrowser(tabControl.SelectedTab);
webBrowser.OpenUrl(url);
}
catch(SpecificException ex)
{
MyApplication.HandleException(ex);
}
}
in respect to your comment, try this:
try
{
myCustomWebbrowser.Navigate("yahoo.com");
}
catch(Exception ex) //catch specific exceptions here (catch all is a bad practice)
{
MessageBox.Alert(ex.Message); //just for testing.
}
This article should help you out:
private void AssignEvents()
{
Navigated += myWeb_Navigated;
DocumentCompleted += myWeb_DocumentCompleted;
Navigating += myWeb_Navigating;
NewWindow += myWeb_NewWindow;
DownloadComplete += myWen_DownloadComplete;
}
void myWen_DownloadComplete(object sender, EventArgs e)
{
// Check wheter the document is available (it should be)
if (Document != null)
// Subscribe to the Error event
Document.Window.Error += myWeb_Window_Error;
}
void myWeb_Window_Error(object sender, HtmlElementErrorEventArgs e)
{
// We got a script error, record it
ScriptErrorManager.Instance.RegisterScriptError(e.Url,
e.Description, e.LineNumber);
// Let the browser know we handled this error.
e.Handled = true;
}

.NET C#: WebBrowser control Navigate() does not load targeted URL

I'm trying to programmatically load a web page via the WebBrowser control with the intent of testing the page & it's JavaScript functions. Basically, I want to compare the HTML & JavaScript run through this control against a known output to ascertain whether there is a problem.
However, I'm having trouble simply creating and navigating the WebBrowser control. The code below is intended to load the HtmlDocument into the WebBrowser.Document property:
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.Navigate("http://www.google.com/");
When examining the web browser's state via Intellisense after Navigate() runs, the WebBrowser.ReadyState is 'Uninitialized', WebBrowser.Document = null, and it overall appears completely unaffected by my call.
On a contextual note, I'm running this control outside of a Windows form object: I do not need to load a window or actually look at the page. Requirements dictate the need to simply execute the page's JavaScript and examine the resultant HTML.
Any suggestions are greatly appreciated, thanks!
You should handle the WebBrowser.DocumentComplete event, once that event is raised you will have the Document etc.
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
// wb.Document is not null at this point
}
Here is a complete example, that I quickly did in a Windows Forms application and tested.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
wb.Navigate("http://www.google.com");
}
private void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
// wb.Document is not null at this point
}
}
Edit: Here is a simple version of code that runs a window from a console application. You can of course go further and expose the events to the console code etc.
using System;
using System.Windows;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
[STAThread]
static void Main(string[] args)
{
Application.Run(new BrowserWindow());
Console.ReadKey();
}
}
class BrowserWindow : Form
{
public BrowserWindow()
{
ShowInTaskbar = false;
WindowState = FormWindowState.Minimized;
Load += new EventHandler(Window_Load);
}
void Window_Load(object sender, EventArgs e)
{
WebBrowser wb = new WebBrowser();
wb.AllowNavigation = true;
wb.DocumentCompleted += wb_DocumentCompleted;
wb.Navigate("http://www.bing.com");
}
void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Console.WriteLine("We have Bing");
}
}
}
You probably need to host the control in a parent window. You can do this without breaking requirements by simply not showing the window that hosts the browser control by moving it off screen. It might also be useful for development to "see" that it does actually load something for testing, verification etc.
So try:
// in a form's Load handler:
WebBrowser wb = new WebBrowser();
this.Controls.Add(wb);
wb.AllowNavigation = true;
wb.Navigate("http://www.google.com/");
Also check to see what other properties are set on the WebBrowser object when you instantiate it via the IDE. E.g. create a Form, drop a browser control onto it and then check the form's designer file to see what code is generated. You might be missing some key property that needs to be set. I've discovered many-an-omission in my code in this way and also learned how to properly instantiate visual objects programmatically.
P.S. If you do use a host window, it should only be visible during development. You would hide in some manner for production.
Another approach:
You could go "raw" by tryiing something like this:
System.Net.WebClient wc = new System.Net.WebClient();
System.IO.StreamReader webReader = new System.IO.StreamReader(
wc.OpenRead("http://your_website.com"));
string webPageData = webReader.ReadToEnd();
...then RegEx or parse webPageData for what you need. Or do you need the jscript in the page to actually execute? (Which should be possible with .NET 4.0)
I had this problem, and I did not realize that I had uninstalled Internet Explorer. If you have, nothing will ever happen, since the WebBrowser control only instantiates IE.
The Webbrowser control is just a wrapper around Internet Explorer.
You can set in onto an invisible Windows Forms window to completely instantiate it.

Categories

Resources