一个简单的基于 .NET 的 WebClient,支持 JavaScript






4.71/5 (22投票s)
2006 年 3 月 26 日
5分钟阅读

126231

5230
一个简单的基于 .NET 的 WebClient,支持 JavaScript。
引言
如果您想在 .NET 代码中访问网页,这意味着需要访问 HTML 文档对象模型并评估嵌入的脚本,那么唯一的方法就是包装 Internet Explorer COM 接口 (SHDocVw
)。但这种方法有一些主要的缺点。
最大的缺点是无法捕获 alert()
或 confirm()
脚本调用。这意味着,如果您使用 SHDocVw
库在 .NET 代码中加载网页,并且其中包含嵌入的 alert('Hello World');
调用,您的程序将等待用户按下“确定”按钮。
另一个缺点是无法在同一进程中创建两个或更多具有不同 Cookie 存储的 Internet Explorer 实例。在您的运行时中实例化的所有浏览器都将共享相同的资源,因此您无法在基于 Cookie 的网页上同时以两个用户的身份登录。对此有一个解决方法(通过 System.Diagnostics.Process
启动两个或更多 iexplore.exe,并将它们连接到您的运行时中的 COM 对象),但这会导致不可预测的行为,例如如果您的程序未正常关闭,会留下 iexplore.exe 实例。
就我而言,我需要一个简单的 WebClient,它允许我访问基本的 HTML 文档对象模型对象和简单的 JavaScript 代码(例如评估默认的 ASP.NET 客户端验证器)。
必备组件
要构建一个支持 JavaScript 的 WebClient,我们至少需要以下三个基本组件:HTTP 协议实现、HTML 文档对象模型和 JavaScript 引擎。.NET 已经提供了许多内置类型来处理至少类似的任务,我们将尽可能地重用它们。
HTTP 协议实现
类型 System.Net.HttpWebRequest
和 System.Net.HttpWebResponse
实现 HTTP 协议,因此非常适合我们的工作。它们可以处理 GET 和 POST 请求,允许我们读取和写入 HTTP 标头,并且能够建立 HTTP 和 HTTPS 连接。
HTML 文档对象模型
目前,.NET 框架不支持 HTML 对象模型。但由于 HTML 与 XML 非常相似,我们将使用 System.Xml.XmlDocument
并对其进行扩展以满足我们的需求。
JavaScript 引擎
.NET 框架提供了一个名为“JScript.NET”的 JavaScript 实现。它可以通过 Microsoft.JScript.Vsa
(Visual Studio for Application) 框架访问,并且可以轻松用于我们的目的。
实现
Cb.Web.WebClient
Cb.Web.WebClient
类型非常直接。它有一个空的默认构造函数,一个 void Get(string url);
方法,并且可以通过 myWebClient.Window.Document
访问 HTML 文档对象模型。
它有两个事件,用于处理诸如 alert (OnAlert
) 和 confirm (OnConfirm
) JavaScript 调用之类的对话框,以及一个用于捕获 JavaScript 错误 (OnError
)。
// Basic example
WebClient myWebClient = new WebClient();
myWebClient.OnAlert += new AlertHandler(WebClient_OnAlert);
myWebClient.Get("http://www.thecodeproject.com/");
Cb.Web.Html.HtmlDocument
如前所述,可以通过 WebClient 的 Window.Document
属性访问 HTML 文档对象模型。该接口基本上是默认浏览器 DOM 接口(即提供 GetElementById
、GetElementsByTagName
或 Body
等方法)。
myWebClient.Window.Document.GetElementById("Email").
SetAttribute("value", email);
myWebClient.Window.Document.GetElementById("Password").
SetAttribute("value", password);
myWebClient.Window.Document.Forms["subForm"].Submit();
通过扩展 System.Xml.XmlDocument
,我们拥有了一个 XML 文档的所有功能,例如 XPath 查询(SelectSingleNode
、SelectNodes
)。
用于填充 HtmlDocument
的 Cb.Web.Html.HtmlReader
类型是一个非常基础的、非验证的 HTML 解析器。在当前状态下,它不会抛出任何解析错误,但可能会丢失一些标签或属性。我没有使用文章 Convert HTML to XHTML and clean unnecessary tags and attributes 中提到的 SgmlReader
,因为我无法找到一种简单的方法来用它填充我们的 DOM。
Cb.Web.Scripting
为了实现我们的 JavaScript 引擎,我使用了 Microsoft.JScript.Vsa.VsaEngine
。Mark Belles 的精彩文章 VSA Scripting in .NET 中解释了基本用法。
此实现中有趣的部分是隐藏我们 DOM 对象的 .NET 签名并提供标准的 DOM 级别签名,以及为所有脚本对象添加 expando 功能。“Expando”意味着能够随时将属性附加到任何对象。
为了实现这些功能,所有填充到我们脚本引擎的对象都继承自 System.Reflection.IReflect
。这样,我们的对象就被强制要求提供一个名为 MemberInfo[] GetMember(name)
的方法,该方法将被 VsaEngine
用于解析属性和方法。
class HtmlDocument : IReflect {
// Note: this example is stripped, its main purpose is to show you
// the idea behind expando objects and property/method resolving
public MemberInfo[] GetMember(string name) {
switch (name) {
case "getElementById": return GetType().GetMember("GetElementById");
}
// ... handle expando properties ...
}
}
Expando 属性是通过在上述方法中创建动态 FieldInfo()
来实现的,该方法通过绑定的 Hashtable
对象存储或获取其值。这样,像这样的脚本就可以工作了
document.MyVar = "World";
alert("Hello " + document.MyVar);
// Will alert 'Hello World'
最终注释
在其当前状态下,附带的源代码可以处理简单的网页并评估简单的 JavaScript 源。目前它(基本上)没有 CSS 支持,也没有真正的 DOM 合规性。其性能也不是最顶尖的,但它可以在基本的 ASP.NET 网页上运行,并且可以在多线程环境中使用。
附带的演示程序显示了其当前已实现的大部分功能。它打开“www.thecodeproject.com”,搜索我的一个文章,如果您修改源代码并提供您的用户名和密码,它将给该文章打 5 分 ;-)。顺便说一句,我删除了 try/catch
块,该块在失败时会给它打 1 分……
版本
版本 1.0 (发布于 2006 年 3 月 26 日)
- 初始发布。