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?
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";
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With