问题描述
我正在使用 C# 和 .NET 3.5.如您所知,我们可以像这样在 Web 浏览器控件上的 Navigate()
中添加自定义标头:
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) + "
" +
"User-Agent: MyUserAgent
";
webTDW8961nd.Navigate(uri, "", null, authHeader);
在上面的示例中,我们为单个导航设置了基本授权标头.
In the example above we set a Basic Authorization header for a single navigation.
现在让我们谈谈重定向.如果我们要执行将重定向到另一个页面的 javascript,则不会包含 Basic Authorization 标头.
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?
推荐答案
问题在于,虽然 WinForm 和 WPF 的 WebBrowser
都只是 ActiveX IE 控件的一个相对薄的包装器,但它们并没有不要向我们公开所有感兴趣的事件(第二个提供的甚至比第一个少).有两种方法可以解决这个问题:首先,子类化 WF 浏览器控件并添加您需要的内容,或者使用 WPF 并在其中添加挂钩.我发现第二种方法在 WPF 应用程序中更方便.
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.
您只需要相关的接口.最简单的方法是添加对 Microsoft Internet Controls 的引用(您会在 COM 标题下发现它是 VS).这将打开一个名为 SHDocVw
的命名空间,其中包含我们需要的所有内容(如果出于任何原因,您想摆脱这种依赖关系,您可以简单地将使用的 P/Invoke 接口复制到您自己的代码中).
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).
您可以使用反射获取底层浏览器.如果你过早调用它会返回 null
,所以我把它放到 WebBrowser.Navigating
处理程序中:
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;
有两个事件接口,2
变体包含较新的事件.您可以在 MSDN 上查看所有这些内容.一个>
There are two event interfaces, the 2
variant contains the newer events. You can look all this up on MSDN.
然后,回到标题:BeforeNavigate2
事件允许您将额外的标题放入提供的对象中:
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
";
}
这篇关于为 C# 中的所有请求向 Webbrowser 控件添加自定义标头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!