2

I'm quite new at c# and am trying to build a program that logs into a website and returns it's source code. Problem is, I register an event listener for when the page is loaded, but when I debug it it quits after setting the same event, not actually doing what I want it to do after the page "loads".

Here's the source -

using System;
using System.Windows.Forms;

namespace WIN
{
    class Program
    {
        string url = -snip-;
        string username = -snip-;
        string password = -snip-;
        string task = -snip-;
        string action = -snip-;
        string timezone = -snip-;

        private void Login()
        {
            Console.WriteLine("Started.");
            Console.ReadLine();
            Console.WriteLine("Declaring WebBrowser instance browser...");
            WebBrowser browser = new WebBrowser();
            Console.WriteLine("Done.");
            Console.ReadLine();
            Console.WriteLine("Registering an event for when the page finishes loading...");
            browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(pageLoaded);
            Console.WriteLine("Done.");
            Console.ReadLine();
            Console.WriteLine("Using method Navigate of browser instance with url parameter...");
            browser.Navigate(url);
            Console.WriteLine("Done.");
            Console.ReadLine();

        }

        private void pageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            Console.WriteLine("Declaring WebBrowser instance browser as sender...");
            WebBrowser browser = sender as WebBrowser;
            Console.WriteLine("Done.");
            Console.ReadLine();
            string response = browser.DocumentText;

            Console.WriteLine("Searching for authenticity token...");
            // looks in the page source to find the authenticity token.
            // could also use regular expressions here.
            int index = response.IndexOf("authenticity_token");
            int startIndex = index + 41;
            string authenticityToken = response.Substring(startIndex, 40);
            Console.WriteLine("Found authenticity token.");

            Console.WriteLine("Unregistering first event handler...");
            // unregisters the first event handler
            // adds a second event handler
            browser.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(pageLoaded);
            Console.WriteLine("Done.");
            Console.WriteLine("Adding second event handler...");
            browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(pageLoaded2);
            Console.WriteLine("Done.");
            Console.Read();

            Console.WriteLine("Formatting data to be posted to server...");
            string postData = string.Format("_user={0}&_pass={1}&authenticity_token={2}&_task{3}&_action{4}&_timezone{5}", username, password, authenticityToken, task, action, timezone);
            Console.WriteLine("Done.");
            Console.Read();

            Console.WriteLine("Declaring ASCIIEncoding instance enc...");
            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            Console.WriteLine("Done.");
            Console.Read();

            //  we are encoding the postData to a byte array
            Console.WriteLine("Encoding postData to a byte array...");
            browser.Navigate(url, "", enc.GetBytes(postData), "Content-Type: application/x-www-form-urlencoded\r\n");
            Console.WriteLine("Done..");
            Console.Read();

        }

        [STAThread]
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Login();
        }
    }
}

From all those console outputs, it only gets to Using method Navigate of browser instance with url parameter...

HolyThunder
  • 463
  • 1
  • 6
  • 17

1 Answers1

5

WebBrowser requires that your program pumps a message loop. It won't fire its events otherwise. This is in general a requirement for any program that uses a single-threaded COM component. Or to put it in more understandable terms: you can't get a program to be busy reading from the console and at the same time fire events like DocumentCompleted. A thread can do only one thing at time. You pump a message loop by writing a Winforms app or starting one yourself with Application.Run(). With a message loop, a thread can do more than one thing at a time. But that does require very different code from what you've written right now, you still can't use Console.ReadLine(), you'd use a TextBox instead.

You can rescue what you have by running the browser in a separate thread, you'll find the code you need for that in this answer.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I'm just using Console.Read(); for debugging purposes. If I remove them will the program work? – HolyThunder May 23 '12 at 13:43
  • Also, I thought the [STAThread] solved that. Anyway, I'm no pro at c#, but I'll try to use the code in the answer you linked to. – HolyThunder May 23 '12 at 13:44
  • When you remove the Console.Read calls then your program will just immediately terminate because there's nothing to stop it racing through the code. You need to seriously consider switching to a Winforms or WPF app, a console mode app just gets you into too much trouble. It's okay for simple apps but running a browser in your program just isn't that simple. – Hans Passant May 23 '12 at 13:47
  • Look, I'm a complete noob at c#. Would you mind explaining what a Winforms app or WPF? I don't need, nay, I don't want a visual component. – HolyThunder May 23 '12 at 13:49