The flow of browsing the web and executing scripts in a web browser

I'm really struggling to grasp the logic behind this function I'm working on.

    public void PortalLogin(AutoResetEvent signal)
            {
                // Navigate to portal
                string portalUrl = "website_name";
                string portalEmail = "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cca9a1ada5a08ca9a1ada5a0e2afa3a1">[email protected]</a>";
                string portalPassword = "password";
                Action action2 = () =>
                {
                    webBrowser2.Tag = signal;
                    webBrowser2.Navigate(portalUrl);
                    webBrowser2.DocumentCompleted -= WebBrowserDocumentCompleted;
                    webBrowser2.DocumentCompleted += WebBrowserDocumentCompleted;
                };
                webBrowser2.Invoke(action2);
                signal.WaitOne();

                // Login to O365 portal
                webBrowser2.Invoke(new Action(() =>
                {
                    HtmlElement head = webBrowser2.Document.GetElementsByTagName("head")[0];
                    HtmlElement testScript = webBrowser2.Document.CreateElement("script");
                    IHTMLScriptElement element = (IHTMLScriptElement)testScript.DomElement;
                    element.text = "function PortalLogin() { document.getElementById('userid').value = '" + portalEmail + "'; document.getElementById('password').value = '" + portalPassword + "';  document.getElementById('login').submit(); }";
                    head.AppendChild(testScript);
                    webBrowser2.Document.InvokeScript("PortalLogin");
                }));
            }

... more functions after this

As I debug, it appears that the

document.getElementById('login').submit();
part of the script is not being executed at the right moment. How can I ensure that nothing proceeds until the InvokeScript has been fully completed?

If there are any unnecessary lines of code or areas that can be tidied up, I would greatly appreciate any feedback on that too.

UPDATE: Below is the DocumentCompleted function.

private void WebBrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs Url)
        {
            ((AutoResetEvent)((WebBrowser)sender).Tag).Set();
        }

Answer №1

Let me highlight a few key points:

To streamline your code, consider adding the DocumentCompleted event handler outside the PortalLogin function and reuse it whenever needed. Since you are using AutoResetEvent, which automatically resets to a non-signaled state after calling signal.WaitOne(), having just one permanent handler for DocumentCompleted should suffice.

Before invoking the InvokeScript method, make sure that document.getElementById('login') indeed returns a valid element with the submit method available. You could even split the login process into two distinct steps for better control.

            // Code block for setting up login function and executing it
            element.text = "function PortalLogin() { document.getElementById('userid').value = '" + portalEmail + "'; document.getElementById('password').value = '" + portalPassword + "';  }" +
                "function ExecuteLogin() { document.getElementById('login').submit(); }";
            head.AppendChild(testScript);
            webBrowser2.Document.InvokeScript("PortalLogin");
            // Verify the presence of 'login' element before proceeding
            webBrowser2.Document.InvokeScript("ExecuteLogin");

If the login is successful, another DocumentCompleted event would be triggered eventually.

I recommend refactoring this code using a single thread and implementing the await/async pattern. Transforming DocumentCompleted as a task with TaskCompletionSource (explained in this reference) can significantly enhance the readability and efficiency of your code.

Here's an example snippet showcasing how the implementation might look like with async/await. Replace instances of MessageBox.Show with your DOM manipulations for a smoother experience on the main UI thread.

// Code block demonstrating async/await pattern 
void Form1_Load(object sender, EventArgs e)
{
    var task = DoNavigationAsync();
    task.ContinueWith((t) =>
    {
        MessageBox.Show("Navigation done!");
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

// Skeleton structure for TaskCompletionSource parameter
struct Void {};

async Task DoNavigationAsync()
{
    Void v;
    TaskCompletionSource<Void> tcs = null; 
    WebBrowserDocumentCompletedEventHandler documentComplete = null;

    documentComplete = new WebBrowserDocumentCompletedEventHandler((s, e) =>
    {
        // Omit additional DocumentCompleted events to ensure a smooth navigation flow
        this.WB.DocumentCompleted -= documentComplete;              
        tcs.SetResult(v); // Proceed from where awaited
    });

    // Navigate to www.bing.com
    tcs = new TaskCompletionSource<Void>();
    this.WB.DocumentCompleted += documentComplete;
    this.WB.Navigate("http://www.bing.com");
    await tcs.Task;
    MessageBox.Show(this.WB.Document.Url.ToString()); // Perform desired actions with WB.Document

    // Repeat similar process for other URLs like www.google.com and www.yahoo.com

    return;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Transforming DOM elements into Objects

Here are some values that I have: <input name="Document[0][category]" value="12" type="text"> <input name="Document[0][filename]" value="abca.png" type="text" > I am looking for a way to convert them into an object using JavaScript or jQuer ...

Having some trouble identifying the specific name of the item I require in C# using Newtonsoft JSON. It seems quite

I have parsed a JSON document into a hashtable and initiated a foreach loop through the Dinnersets within it. In my Helper class, I have saved the current DinnerSet and now I just need to utilize a string called CurrentMeal, which holds a mealname, like s ...

Make sure that the webpage does not display any content until the stylesheet has been fully loaded by

I am seeking to utilize ng-href for loading different Themes. One issue I am encountering is that the unstyled content appears before the stylesheet is applied. I have created a Plunker where I made changes to Line 8 in the last 3 Versions for comparison ...

What could be causing the strange output from my filtered Object.values() function?

In my Vue3 component, I created a feature to showcase data using chips. The input is an Object with keys as indexes and values containing the element to be displayed. Here is the complete code documentation: <template> <div class="row" ...

Guide to selecting and clicking multiple elements with a specific class using jQuery

On my html page, I have the following elements: $(".pv-profile-section__card-action-bar").length 3 I want to click on all of these elements instead of just the first one. Currently, I am achieving this with the code: $(".pv-profile-section__card-action- ...

Is there a universal method to disregard opacity when utilizing jQuery's clone() function across different web browsers?

I've encountered a situation where I need to allow users to submit a new item to a list within a table, and have it smoothly appear at the top of the list. While using DIVs would make this task easier, I am working with tables for now. To achieve thi ...

Identify whether the page is being accessed through the Samsung stock browser or as an independent web application

Hey there! I am on a mission to determine whether my webpage is being accessed through Samsung's default browser or as a standalone web app saved on the homescreen. Unfortunately, the javascript codes I have come across only seem to work for Safari an ...

Display only the most recent AJAX results

There are times when I encounter a scenario where performing an action on the page triggers an ajax request. If multiple actions of this nature happen in quick succession, each ajax request performs its task (such as updating a list of items) one after t ...

Is there a method to globally import "typings" in Visual Code without having to make changes to every JS file?

Is there a method to streamline the process of inputting reference paths for typings in Visual Studio Code without requiring manual typing? Perhaps by utilizing a configuration file that directs to all typings within the project, eliminating the need to ...

transform array elements into an object

I encountered the following code snippet: const calcRowCssClasses = (<string[]>context.dataItem.cssClasses).map( (cssClass) => { return { [cssClass]: true }; } ); This code block generates an array of objects like ...

Angular Material (8) error code S2591: The variable 'require' is not defined in the current scope

Currently, I am attempting to record the date and time in the JavaScript console. Despite the code successfully logging the dates, an error message persists: Note: The code is functioning properly, with the dates being displayed in the console. It is only ...

Sticky positioning with varying column widths

How can I create HTML and CSS columns that stick together without manually specifying the "left:" parameter every time? The current example in the fiddle achieves what I want, but requires manual setting of the "left:" value. Is there a way to make this m ...

Guide on creating and synchronizing an XML/JSON file that stores beat information (BPM) for audio using JavaScript

Looking to sync Javascript events with the BPM of music for a game similar to "Guitar Hero." We start with: In order to create a track file based on beat detection (with each BPM saved like sheet music), how can it be generated beforehand rather than in ...

Tips for populating countryList data in Form.Select component within a React.js application

I have a data file that contains a list of all countries, and I need to display these countries in a select input field, similar to what you see on popular websites when a user logs in and edits their profile information like name, address, and country. H ...

Enable Cursor Display in Readonly Input Fields

Consider this scenario: Setting an input field to .readOnly = true replaces the text cursor with a pointer arrow cursor, preventing users from entering or modifying the field. Interestingly, clicking into a readonly input field that already contains text s ...

``Trouble with React Dropdown menu option selection"

I am encountering challenges with implementing a dropdown menu list for my react app. The issue at hand is that I have an API where one of the keys (key3) has values separated by commas that I wish to display in my dropdown list. The structure of the API ...

"Troubleshooting a callback problem in jQuery involving JavaScript and AJAX

UPDATE3 and FINAL: The problem has been resolved with the help of Evan and meder! UPDATE2: To clarify, I need the existing function updateFilters(a,b) to be called, not created. My apologies for any confusion. The issue with the code below is that udpate ...

Unable to create a clickable button within a CSS3DObject using Three.js

How can I create an interactive button on a CSS3DObject within a cube made up of 6 sides? The button is located on the yellow side, but I'm facing issues with clicking on it. Whenever I attempt to click on the button, the event.target always points to ...

"Pairing Angular's loader with RxJS combineLatest for seamless data

Hey there! Currently, I'm working on enhancing my Angular application by implementing a global loader feature. This loader should be displayed whenever data is being fetched from my API. To achieve this, I am utilizing ngrx actions such as fetchDataAc ...

Unable to render page with scrapy and javascript using splash

I am currently trying to crawl this specific page. Following a guide on Stack Overflow to complete this task, I attempted to render the webpage but faced issues. How can I resolve this problem? This is the command I used: scrapy shell 'http://local ...