Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a customized header to Webbrowser control for all requests in C#?

I'm using C# and .NET 3.5. As you know, we can add custom header to Navigate() on the web browser control like this:

var myUrl = "http://example.com/mypage.htm";
System.Uri uri = new Uri(myUrl);

byte[] authData = System.Text.UnicodeEncoding.UTF8.GetBytes("user:password");
string authHeader = 
    "Authorization: Basic " + Convert.ToBase64String(authData) + "\r\n" +
    "User-Agent: MyUserAgent\r\n";

webTDW8961nd.Navigate(uri, "", null, authHeader);

In the example above we set a Basic Authorization header for a single navigation.

Now let talk about redirection. If we want to execute javascript which will redirect to another page, the Basic Authorization header won't be included.

What is your solution? How can I add a header which works for all of the requests and not only once?

like image 900
asDca21 Avatar asked Mar 13 '23 18:03

asDca21


2 Answers

The problem is that while both WinForm's and WPF's WebBrowser are nothing else but a relatively thin wrapper around the ActiveX IE control, they don't expose all the events of interest to us (and the second provides even less than the first). There are two ways to solve this: first, to subclass the WF browser control and add what you need or to use the WPF one and add the hooks there. I found the second approach to be more convenient in a WPF application.

You only need the relevant interfaces. The easiest way is to add a reference to Microsoft Internet Controls (you'll find this under the COM heading is VS). This opens up a namespace called SHDocVw that contains all we need (if, for any reason, you want to get rid of this dependency, you can simply copy the P/Invoke interfaces used into your own code).

You can get the underlying browser using reflection. It will return null if you call it too early, so I put it into the WebBrowser.Navigating handler:

using SHDocVw;
var ActiveXInstance = (IWebBrowser2)Browser.GetType().InvokeMember("ActiveXInstance", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, Browser, new object[] { });

As soon as you have it, you can do nice things with the browser. For instance, you can use various properties and methods not exposed directly:

ActiveXInstance.Silent = true; // suppresses script error dialogs

and add the missing event hooks:

var SetupEvents2 = (DWebBrowserEvents2_Event)ActiveXInstance;
SetupEvents2.BeforeNavigate2 += OnBeforeNavigate2;

There are two event interfaces, the 2 variant contains the newer events. You can look all this up on MSDN.

And, back to the headers: the BeforeNavigate2 event allows you to put your extra headers into the provided object:

private void OnBeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) {
  Headers = $"Accept-Language: XX;en\r\n";
}
like image 79
Gábor Avatar answered Mar 17 '23 10:03

Gábor


To add custom header for each request you can implement extension method:

public static class WebBrowserExtensions
{
    public static void NavigateWithAuthorization(this WebBrowser browser, Uri uri)
    {
        byte[] authData = System.Text.Encoding.UTF8.GetBytes("user:password");
        string authHeader = "Authorization: Basic " + Convert.ToBase64String(authData) + "\r\n" + "User-Agent: MyUserAgent\r\n";
        browser.Navigate(uri, "", null, authHeader);
    }
}

And then call it instead of standard method:

//browser.Navigate(uri, "", null, authHeader);
browser.NavigateWithAuthorization(uri);

The second question is about redirecting. But your scenario will not work in a simple browser and fiddler. It is the feature of web protocol, when you redirect to another Uri you initiate new request with new properties. You can compose your request in js code.

like image 25
Vadim Martynov Avatar answered Mar 17 '23 10:03

Vadim Martynov