As per this article, I've extended the
System.Windows.Forms.WebBrowser class to implement custom error-handling. Mostly, it works.
The problem comes when the browser gets a "401 Unauthorized" response. That kind of response causes the
WebBrowser control to display the standard Username / Password dialog. The
NavigateError event isn't fired until that dialog is cancelled.
So what can I do to capture the 401 response and handle it in my own custom way?
I assumed there would be something I could do, such as that which I do to capture the
NavigateError event, and handle those my own way but I haven't seen anything.
Edit: Solution Found!
The important steps are:
1. The WebBrowser control must first be navigated to a non-secure page ("about:blank" is the typical URL used) in order to avoid KB 320153
2. The host for the WebBrowser control must implement
IServiceProvider.QueryService must handle the
IAuthenticate service request with the
IAuthenticate implementation, all other service requests can be handled with the
IAuthenticate.Authenticate is your custom authentication handler.
implement IAuthenticate and IAuthenticateEx on your webbrowser host. Basically, your IOleClientSite implementation needs to responde IServiceProvider.QueryService, and return an IAuthenticate(Ex) interface (not the managed one, the native one returned from Marshal.GetComInterfaceForObject) when the service is IID_IAuthenticate. For unrecognized service requests, QueryService should return INET_E_DEFAULT_ACTION.
I don't think the WPF webbrowser has extension points for its IOleClientSite implementation. You can try host a Winform webbrowser class which has an overriden CreateWebBrowserSiteBase virtual method that provides the IAuthenticate(Ex) implementation, or write a webbrowser wrapper from the ground up.
This may not work in a Citrix session.
I found that to be able to navigate the site without the Authorization Header getting lost or removed I had to do the following otherwise for each new page the user was prompted again. This solution also does not require the user:[email protected] syntax to be enabled.
private bool _redirected = false;
private const string BaseUrl = @"http://mySite";
private void Navigate()
var helpUrl = BaseUrl;
var authHeader = GetAuthHeader();
_docWindow.Browser.Navigate(helpUrl, string.Empty, null, authHeader);
_docWindow.Browser.Navigating += Browser_Navigating;
private string GetAuthHeader()
byte authData = UnicodeEncoding.UTF8.GetBytes(_userName + ":" + _password);
string authHeader = "Authorization: Basic " + Convert.ToBase64String(authData);
void Browser_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)
_redirected = false;
var newPage = BaseUrl + e.Uri.AbsolutePath;
e.Cancel = true;
_redirected = true;
_docWindow.Browser.Navigate(newPage, string.Empty, null, GetAuthHeader());