网页源代码传输器:获取客户看到的页面






4.88/5 (22投票s)
本文介绍了一个控件,它允许以用户所见的方式获取网页。例如,开发人员可以保存异常发生前的页面副本,并在需要时恢复该页面。
引言
没有 bug 的 Web 应用程序——这是一种神话。
当需要重现客户的 bug 时,每个开发人员都会遇到很多问题。通常,客户无法提供足够的关于异常发生前条件的信息(他们输入的字段值;异常发生前打开的页面等)。
如果应用程序能够生成(恢复)打开的网页的源代码,包括输入的数据,就像异常发生前那样,并将其保存(例如,保存到数据库中),那将非常有帮助。在这种情况下,开发人员可以从(例如,从数据库中)获取页面的源代码,将其放入 HTML 文件并在浏览器中打开。开发人员将获得异常发生前页面的副本。
我将此功能实现为一个非可视控件。
背景
当我开始这个项目时,我以为我可以利用 IHttpModule
的实现来截获应用程序将发送给客户端的 HTML 源,这样就足够了。但是,支持 AJAX 的应用程序只向客户端发送页面的部分更改。在这种情况下,我需要合并完整的渲染和部分渲染才能获得页面的实际状态——这很不方便。
不幸的是,此解决方案不允许将更改的字段和其他更改(例如,由 JavaScript 引起)包含在源代码中。此外,我还需要解析 HTML 代码并设置更改后的值。在我看来,这是一个复杂的解决方案。
然后,我决定采取另一种方法来解决这个问题。我可以在客户端收集 HTML 源、更改的字段等,然后将其发送到服务器!
使用控件
将控件添加到网页非常简单。在 VS.NET 中,您应该使用“添加/删除工具箱项”来选择控件的 DLL 文件(PauSoft.Web.dll)。控件将出现在工具箱中,您可以将其添加到页面。
注意:每个页面或母版页只能添加一个控件实例。
设计器

控件的设计器非常简单。
在设计时,开发人员可以访问 Enabled
属性。默认情况下,它是 true
,但开发人员可以将其切换到 false
来关闭控件的功能(当所有 bug 都已修复时,这对于减小生产环境中的 HTTP 请求大小可能很有用)。
如果应用程序中有母版页,可以将控件添加到母版页中。
如果开发人员有页面或母版页的层次结构,他可以在运行时将控件添加到层次结构的开头。
代码
以下代码描述了如何使用该控件
ASP.NET 母版页声明
<%@ Register Assembly="PauSoft.Web" Namespace="PauSoft.Web.UI.Controls"
TagPrefix="psControls" %>
<psControls:HtmlSourceTransmitter ID="HtmlSourceTransmitter1" runat="server">
</psControls:HtmlSourceTransmitter>
ASP.NET 母版页代码隐藏类
public partial class Site1 : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string htmlSource = HtmlSourceTransmitter1.HtmlSource;
//store htmlSource to DB, file etc
//...
}
}
}
运行时创建控件
运行时创建控件没有任何问题。
以下代码将在页面上添加一个 HtmlSourceTransmitter
,并提供一种方便的方式来访问 HTML 源。
public partial class _Default : MyCustomPage
{
private HtmlSourceTransmitter _htmlTransmitter =
new HtmlSourceTransmitter();
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Controls.Add(_htmlTransmitter);
}
/// <summary />
/// Returns HTML source of the page before submit.
/// </summary />
public string HtmlSource
{
get
{
return _htmlTransmitter.HtmlSource;
}
}
}
它是如何工作的?
HTML 源从客户端传输到服务器有一些步骤。
步骤 1
在 OnPrerender
事件上,控件会检查 Enabled
属性,如果属性值为 true
,则注册脚本。
public class HtmlSourceTransmitter : Control
{
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (Enabled)
RegisterScripts();
}
}
第二步
控件注册一个 JavaScript 处理程序,该处理程序将在客户端的 OnSubmit
事件上执行,以及一个将包含传输 HTML 代码的隐藏字段。
public class HtmlSourceTransmitter : Control
{
private void RegisterScripts()
{
//Register script from .js file depends on current compile mode
//(debug/release) of web application
Page.ClientScript.RegisterClientScriptResource(GetType(),
Utils.GetJSResourceCompilationMode
("PauSoft.Web.Resources.Scripts.HtmlSourceTransmitter.js"));
//Register action, that will be executed on Form OnSubmit event
string scriptName = string.Format(CultureInfo.InvariantCulture,
"{0}_OnSubmit", ClientID);
string scriptText = "FillTransmitterField()";
if (!Page.ClientScript.IsOnSubmitStatementRegistered
(GetType(), scriptName))
Page.ClientScript.RegisterOnSubmitStatement(GetType(),
scriptName, scriptText);
//Register hidden field, that will keep HTML source of the page
Page.ClientScript.RegisterHiddenField(transmitterFieldName, string.Empty);
}
}
步骤 3
在 OnSubmit
事件上,将执行 FillTransmitterField()
函数,该函数将生成一个用于更改元素的更新脚本,将此脚本添加到 Body 元素的 OnLoad
中,并将页面的 HTML 源存储到隐藏字段中,最后将数据发送到服务器(请参阅“HtmlSourceTransmitter.debug.js”文件)。
步骤 4
开发人员可以根据需要使用传入的信息。
结果
下面是一些控件用法的示例

HtmlSourceTransmitter
获取的第一个示例页面的视图
HtmlSourceTransmitter
获取的第二个示例页面的视图
您可以比较屏幕截图和视图——它们几乎一样!
谁可以使用它?
在我看来,几乎所有的用户都一样——他们健忘。在这种情况下,在异常发生前拥有页面的“屏幕截图”非常有用。该控件对于应该捕获服务器 bug 但无法详细描述 bug 前情况的用户很有用。
我们几乎所有人都经历过描述的情况,这个控件可以帮助我们解决问题!
已知问题
HtmlSourceTransmitter
与 Microsoft IE WebControls 库中的TabStrip
控件配合使用效果不佳。- 此控件仅存储显示页面的 HTML 代码,不存储外部资源——图像、脚本、级联样式等。因此,为了获得最佳结果,开发人员应该在应用程序文件夹中创建一个具有接收到的源代码的 HTML 文件。
- 使用
HtmlSourceTransmitter
获取的页面布局可能与原始页面布局不同。
我相信还有一些其他需要修改的事情,或者需要添加的其他功能。所以,请告诉我。
致谢
感谢以下帮助过我的人
- Vladimir Kuznetsov
- Yan Oreshchenkov
- Sergey Zyrianov
历史
- 版本 1.0 (2007-08-30) - 初始发布