c# webbrowser control does not navigate to another page - c#

I have a console application and i've defined a webbrowser inside it.
Firstly, i navigate to a page and fill a login form and invoke the submit button to login.
After that, i want to go to another page in the same site using the same webbrowser but it does not navigate to that page. instead, it navigates to the page that it's redirected after login.
Here is my code for clarification; this code gives me the source code of www.websiteiwanttogo.com/default.aspx instead of product.aspx
what is wrong here?
static WebBrowser wb = new WebBrowser();
[STAThread]
static void Main(string[] args)
{
wb.AllowNavigation = true;
wb.Navigate("https://www.thewebsiteiwanttogo.com/login.aspx");
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
Application.Run();
}
static void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (wb.Url.ToString().IndexOf("login.aspx") > -1)
{
wb.Document.GetElementById("txtnumber").SetAttribute("value", "000001");
wb.Document.GetElementById("txtUserName").SetAttribute("value", "myusername");
wb.Document.GetElementById("txtPassword").SetAttribute("value", "mypassword");
wb.Document.GetElementById("btnLogin").InvokeMember("click");
}
else
{
//wb.Document.Body you are logged in do whatever you want here.
wb.Navigate("https://www.thewebsiteiwanttogo.com/product.aspx");
Console.WriteLine(wb.DocumentText);
Console.ReadLine();
Application.Exit();
}
}

There are a lot of different ways to accomplish this functionality. However, my guess is that:
Either the call to navigate to the next page is happening too quickly, or
The Document.Completed event is not firing properly after logging in (this is common especially if the destination document contains dynamic scripts)
I've done a lot of web page automating (navigating from link to link, then performing some actions, then navigating to another link, etc.), and you should consider using async processes. In principle, it is probably always best when dealing with the webBrowser object to use async processes, simply because there are many instances where you need one process to run while you perform other functions.
Without going into too much detail, look at the answer to this question and study the code: Flow of WebBrowser Navigate and InvokeScript
Before trying that implementation, however, you could simply try adding an async await before trying to navigate to the page. (async await is similar to a Thread.Sleep(), but doesn't actually stop the loading of the page, i.e. the "thread").
(Never heard of asynchronous processes before? Check out this tutorial on MSDN).
Try this first:
static void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (wb.Url.ToString().IndexOf("login.aspx") > -1)
{
wb.Document.GetElementById("txtnumber").SetAttribute("value", "000001");
wb.Document.GetElementById("txtUserName").SetAttribute("value", "myusername");
wb.Document.GetElementById("txtPassword").SetAttribute("value", "mypassword");
wb.Document.GetElementById("btnLogin").InvokeMember("click");
}
else
{
//wb.Document.Body you are logged in do whatever you want here.
await Task.Delay(1000); //wait for 1 second just to let the WB catch up
wb.Navigate("https://www.thewebsiteiwanttogo.com/product.aspx");
Console.WriteLine(wb.DocumentText);
Console.ReadLine();
Application.Exit();
}
}
If this doesn't help, consider the link above and try implementing a more robust navigating sequence with async processes.
If that doesn't work, and you'd like some help navigating through or waiting for dynamic pages to load, try this post: how to dynamically generate HTML code using .NET's WebBrowser or mshtml.HTMLDocument?
I've used this code theology many times, and it works great.
Hope one of these methods helps! Let me know, and I can help you generate some more specific code snippets.
EDIT:
At second glance, I'm going to guess that the Console.ReadLine() is going to freeze up the navigating of wb.Navigate("https://www.thewebsiteiwanttogo.com/product.aspx");, since it won't happen instantaneously. You'll probably want to add another if statement in the Document.Completed handler to allow wb.Navigate("https://www.thewebsiteiwanttogo.com/product.aspx"); to finish navigating before trying to grab the wb.DocumentText. For example:
static void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (wb.Url.ToString().IndexOf("login.aspx") > -1)
{
wb.Document.GetElementById("txtnumber").SetAttribute("value", "000001");
wb.Document.GetElementById("txtUserName").SetAttribute("value", "myusername");
wb.Document.GetElementById("txtPassword").SetAttribute("value", "mypassword");
wb.Document.GetElementById("btnLogin").InvokeMember("click");
}
else if(wb.Url.ToString().IndexOf("product.aspx") > -1)
{
Console.WriteLine(wb.DocumentText);
Console.ReadLine();
Application.Exit();
}
else
{
//wb.Document.Body you are logged in do whatever you want here.
await Task.Delay(1000); //wait for 1 second just to let the WB catch up
wb.Navigate("https://www.thewebsiteiwanttogo.com/product.aspx");
}
}

Related

How to execute code after blazor page has loaded

So I am trying to execute a method when the page has loaded. The OnAfterRender() override method is too early in my case. the method I am trying to do is in my #code{} block of the razor page.
I basically want to execute getAvailablePrinters when the page is loaded.
as requested my code below:
#code {
private List<string> Printers;
private List<string> LayoutTypes;
private void sendPrint()
private async Task getAvailablePrinters()
{
//get layouts
Layouts = new List<Layout>();
AvailablePrintersRepository availablePrintersRepository = new AvailablePrintersRepository();
try
{
Layouts = await availablePrintersRepository.getAvailablePrintersAsync();
}
catch (Exception e)
{
//show message
}
//sort printers & layouts
Printers = new List<string>();
LayoutTypes = new List<string>();
foreach (Layout layout in Layouts)
{
foreach (string printer in layout.Printers)
{
if (!Printers.Contains(printer))
{
Printers.Add(printer);
}
}
if (!LayoutTypes.Contains(layout.Type))
{
LayoutTypes.Add(layout.Type);
}
}
}
}
#AccessDenied I want to send a request to another API to get back data i need to display to the user. i now have a button to do it but i want to get the data after the page has loaded so the user doesn't have to press the button each time
--
Because the method isn't finished when the page has loaded so that is why I want to do it after the page has loaded
So you believe that the OnAfterRenderAsync and OnAfterRender are called too early in the pipeline, and thus are not fit for the Web Api call you want to do in order to retrieve data, right ?
You are wrong, they are, in my opinion too late for this enterprise, and you should use the OnInitializedAsync life cycle method to execute the HTTP request.
Please see the VS template how a Web Api is made to populate the ForeCast objects
in the FetchData page.
You should try code in various situations to understand how the initialization process works, and see that your ideas or perceptions are wrong. Understand this: You should retrieve your data before your page is rendered, not after it is being rendered. OnAfterRender(Async) may be used to execute code that otherwise it's too early to execute. It is most often used to initialize JS objects.
Hope this helps...

Web Browser logic error with any form of a loop

I am trying to create a simple Kiosk-style web browser for work. This is supposed to rotate between two internet tabs automatically. There will NEVER be any user input. Static web pages, preassigned, and only for display in our main office. I am using a C#.NET WPF app with a TabControl and a web browser in each tab. I can preassign a web page to each tab, easy stuff. What I cannot do is generate the infinite loop to constantly switch between the two tabs. Any loop whatsoever [while(true), for(;;), do-while(true)] will keep the form from loading at all. The code provided is my attempt at just generating the web pages within the loop first, then I'll go back and add the logic for the auto-switching.
namespace LoopNet
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
while(true)
{
Calendar1.Navigate("http://www.google.com");
GIS1.Navigate("http://www.YouTube.com");
}
}
}
}
Add a Loaded event handler and stick it in there.
Anything called on the main thread like that will hang the app. As a comment said, use a Timer.
Note: if the Timer.Elapsed method is doing things TO the UI, then it won't like it. The quick solution to this is to use the Dispatcher invoke method.
you'd end up with something along these lines:
public void CreateTimer()
{
var timer = new System.Timers.Timer(1000); // fire every 1 second
timer.Elapsed += HandleTimerElapsed;
}
public void HandleTimerElapsed(object sender, ElapsedEventArgs e)
{
Application.Current.Dispatcher.Invoke(
() =>
{
//do things on UI thread...
SwitchTheTabs();
}
);

Starting, Stopping A Thread

I am not really sure how thread works.
Here is my code. Upon clicking a send button:
protected void BtnSend_Click(object sender, EventArgs e)
{
Thread threadA = new Thread(SendSMS);
threadA.Start();
}
protected void SendSMS()
{
//some validations here
Thread threadB = new Thread(loadingScreen);
threadB.Start();
threadB.Join();
//code that actually sends the required Mail
threadB.Stop();
loading.Visible = false;
}
threadB is calling this method which is basically a div (called loading) with a loading div that disables user from pressing anything on screen:
protected void loadingScreen()
{
loading.Visible = true;
}
Now the mail is being sent but the loading screen (div) is not becoming visible.
What am I doing wrong?
You have to rethink when you're writing ASP.NET vs. a rich client application. In short (really really short) the web browser (client) sends a request to the server. The server handles that request (that part is your code behind), and returns a result to the web browser.
When you show a DIV in your codebehind, do some work, then hide it again, only the result will arrive at the web browser.
There are multiple ways to achieve the optical effect you want, but you must know about the Life Cycle of ASP.NET first. Start here, for example.
I think you want a responseable application while you compute a huge task.
In WinForms you have to be careful because if you want to change some UI like a Text in a Label you have to synchronize both Threads. (UI-Thread and Thread1)
If you are running .NET 4.0 you should use the Task-Class, because there you don't need to synchronize and you can also use anonymous methods.
protected void SendSMS()
{
loading.Visible = true;
var task = Task.Factory.StartNew(()=>{//code that actually sends the required Mail}
task.Wait();
loading.Visible = false;
}
Actually the loading Gets visible and then hidden quickly. Join returns immediately as soon as it enabled the Div and then the email is sent, the Div is disabled again. Sending email and disabling happens in same thread.
Why do you use threadB? You can do operation only with threadA:
protected void SendSMS()
{
//some validations here
loading.Visible = false;
//code that actually sends the required Mail
loading.Visible = false;
}
Warning for crossthread operation exception.

Web automation using .NET

I am a very newbie programmer. Does anyone of you know how to do Web automation with C#?
Basically, I just want auto implement some simple action on the web.
After I have opened up the web link, i just want to perform the actions below automatically.
Automatically Input some value and Click on "Run" button.
Check In the ComboBox and Click on "Download" button.
How can I do it with C#? My friend introduce me to use Powershell but I guess .Net do provide this kind of library too. Any suggestion or link for me to refer?
You can use the System.Windows.Forms.WebBrowser control (MSDN Documentation). For testing, it allows your to do the things that could be done in a browser. It easily executes JavaScript without any additional effort. If something went wrong, you will be able to visually see the state that the site is in.
example:
private void buttonStart_Click(object sender, EventArgs e)
{
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
webBrowser1.Navigate("http://www.wikipedia.org/");
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement search = webBrowser1.Document.GetElementById("searchInput");
if(search != null)
{
search.SetAttribute("value", "Superman");
foreach(HtmlElement ele in search.Parent.Children)
{
if (ele.TagName.ToLower() == "input" && ele.Name.ToLower() == "go")
{
ele.InvokeMember("click");
break;
}
}
}
}
To answer your question: how to check a checkbox
for the HTML:
<input type="checkbox" id="testCheck"></input>
the code:
search = webBrowser1.Document.GetElementById("testCheck");
if (search != null)
search.SetAttribute("checked", "true");
actually, the specific "how to" depends greatly on what is the actual HTML.
For handling your multi-threaded problem:
private delegate void StartTestHandler(string url);
private void StartTest(string url)
{
if (InvokeRequired)
Invoke(new StartTestHandler(StartTest), url);
else
{
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
webBrowser1.Navigate(url);
}
}
InvokeRequired, checks whether the current thread is the UI thread (actually, the thread that the form was created in). If it is not, then it will try to run StartTest in the required thread.
Check out SimpleBrowser, which is a fairly mature, lightweight browser automation library.
https://github.com/axefrog/SimpleBrowser
From the page:
SimpleBrowser is a lightweight, yet
highly capable browser automation
engine designed for automation and
testing scenarios. It provides an
intuitive API that makes it simple to
quickly extract specific elements of a
page using a variety of matching
techniques, and then interact with
those elements with methods such as
Click(), SubmitForm() and many more.
SimpleBrowser does not support
JavaScript, but allows for manual
manipulation of the user agent,
referrer, request headers, form values
and other values before submission or
navigation.
If you want to simulate a real browser then WatiN will be a good fit for you. (Selenium is another alternative, but I do not recommend it for you).
If you want to work on the HTTP level, then use WebRequest and related classes.
You could use Selenium WebDriver.
A quick code sample below:
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
// Requires reference to WebDriver.Support.dll
using OpenQA.Selenium.Support.UI;
class GoogleSuggest
{
static void Main(string[] args)
{
// Create a new instance of the Firefox driver.
// Note that it is wrapped in a using clause so that the browser is closed
// and the webdriver is disposed (even in the face of exceptions).
// Also note that the remainder of the code relies on the interface,
// not the implementation.
// Further note that other drivers (InternetExplorerDriver,
// ChromeDriver, etc.) will require further configuration
// before this example will work. See the wiki pages for the
// individual drivers at http://code.google.com/p/selenium/wiki
// for further information.
using (IWebDriver driver = new FirefoxDriver())
{
//Notice navigation is slightly different than the Java version
//This is because 'get' is a keyword in C#
driver.Navigate().GoToUrl("http://www.google.com/");
// Find the text input element by its name
IWebElement query = driver.FindElement(By.Name("q"));
// Enter something to search for
query.SendKeys("Cheese");
// Now submit the form. WebDriver will find the form for us from the element
query.Submit();
// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.Title.StartsWith("cheese", StringComparison.OrdinalIgnoreCase));
// Should see: "Cheese - Google Search" (for an English locale)
Console.WriteLine("Page title is: " + driver.Title);
}
}
}
The great thing (among others) about this approach is that you can easily switch the underlying browser implementations, just by specifying a different IWebDriver, like FirefoxDriver, InternetExplorerDriver, ChromeDriver, etc. This also means you can write 1 test and run it on multiple IWebDriver implementations, thus testing how the page works when viewed in Firefox, Chrome, IE, etc. People working in QA sector often use Selenium to write automated web page tests.
I'm using ObjectForScripting to automate WebBrowser, A Javascript callback to C# function and then function in c# extract data or automate many-thing.
I have clearly explained in the following link
Web Automation using Web Browser and C#
.NET does not have any built-in functionality for this. It does have the WebClient and HttpRequest/HttpResponse classes, but they are only building blocks.
You cannot easily automate client-side activity, like filling out forms or clicking on buttons from C#. However, if you look into JavaScript, you may be able to better automate some of those things. To really automate, you would need to reverse engineer the call made by clicking the button, and connect to the url directly, using the classes #John mentions.

How to fix "The requested resource is in use. (Exception from HRESULT: 0x800700AA)"

How can I solve this error?
"The requested resource is in use. (Exception from HRESULT: 0x800700AA)".
This appears while navigating to a different website using the WebBrowser control in C# .NET. Why?
The WebBrowser control is considered "in use" if either a navigation action is currently being processed, or any blocking dialog from the control is currently open (including context menu, Javascript alerts, NTLM login dialog, etc.). You can use the WebBrowser.IsBusy property to detect these states.
If due to a currently incomplete navigation action, you could try to stop the current navigation (if you indeed want to stop when the page is not completed loaded) or add the new navigation to a request queue and use a timer to wait until WebBrowser.IsBusy returns false.
If instead the busy state is due to one or more open blocking dialogs, you could do the same wait technique and perhaps Messagebox.Show() the user a message that pending navigation is delayed due to an open dialog window.
I had this same issue. Calling WebBrowser.Stop() did not help, and WebBrowser.IsBusy never became false.
It turns out that if the page creates any sort of dialog (alert() popups, javascript errors, NTLM login popups etc.) you can't navigate away from the page until the dialog is closed.
My solution was to prevent the dialogs from showing in the first place. Apparently preventing all of these popups is simple; just set
webBrowser.ScriptErrorsSuppressed = true;
bool go = false;
string SiteContent1 = string.Empty;
string SiteContent2 = string.Empty;
int index = 0;
WebBrowser wb = new WebBrowser();
void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
try
{
if (go)
{
SiteContent2 = wb.DocumentText;
// Code to compare to contents of the webbrowser
index++;
go = false;
steps = 1;
}
if (!go)
{
if (index >= TotalSiteCount)
{
Stop();
}
else if (steps == 1)
{
wb.Navigate(UrltocompareList[index].Url1);
}
else if (steps == 2)
{
SiteContent1 = wb.DocumentText;
wb.Navigate(UrltocompareList[index].Url2);
go = true;
}
steps++;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
UrltocompareList is a collection of 2 sites to compare.
TotalSiteCount is the number of items in UrltocompareList.
The form for this inherit IOleClientSite to remove media such as images, videos and no active X download to have a faster rendering time in webbrowser control.
I use this method instead of system.net.webclient to get the html of a webpage then compare them.
I got this error when it hits the wb.Navigate method.
An issue I ran into when running specflow tests with watin in windows 10 is that win10 by default uses MS Edge, so I had never opened IE, and when watin started it IE was stuck on the prompt for using default settings. Selecting options, closing browser and running tests again worked for me.
Just something to watch
This can be solved pretty easily.
This error occurs when the browser commits an action while he's already performing an action.
For example, you are navigating to some website while you rightclick in the web browser.
To solve this, I did the follow:
//if my webbrowser isn't performing any actions
if(!myWebBrowser.IsBusy)
{
//Navigate
myWebBrowser.Navigate("http://www.google.com");
}
First Try
1- Please Check Navigate URL's (if you check, please check again compiled folder)
2- Delete WebBrowser Control and Add New
Me forget copy original file App.Path + "\error.html" and see this problem.
Guarantee Method
I Fix This Error in VB6
Add WebBrowserControl wb(0) (Name wb , Index=0)
And Before Ever Navigate
For i = 1 To wb.UBound
Unload wb(i)
Next
Load wb(1)
wb(0).Visible = False
wb(1).Visible = true
wb(1).Navigate URL

Categories