作为开发者,经常面临一个难题:当客户报告一个bug时,他们往往无法提供足够的信息来描述异常发生前的情况(例如他们输入的字段值、异常发生前打开的页面等)。如果应用程序能够在异常发生前生成(恢复)打开的网页源代码,并将其存储起来(例如存储在数据库中),那么开发者就可以从数据库中获取页面源代码,将其放入HTML文件并在浏览器中打开。这样,开发者就可以得到异常发生前页面的副本。
为了实现这一功能,开发了一个非可视控件。在项目开始时,考虑使用IHttpModule实现来拦截HTML源代码,但AJAX应用程序只会将页面变化的部分发送给客户端。在这种情况下,需要合并完整渲染和部分渲染以获取页面的实际状态,这很不方便。此外,这种方法不允许将更改的字段和其他更改(例如由JavaScript引起的更改)包含在源代码中。还需要解析HTML代码并设置更改的值。在看来,这是一个复杂的解决方案。
然后,决定采用另一种方法来解决这个问题。可以收集客户端的HTML源代码、更改的字段等,然后将其发送到服务器!
在Visual Studio中添加控件非常简单。应该使用“添加/移除工具箱项”选择控件的DLL文件(PauSoft.Web.dll)。控件将出现在工具箱中,可以将其添加到页面中。
注意:只能将控件的一个实例添加到页面或母版页。
设计器非常简单。在设计时,开发者可以访问Enabled属性。默认情况下它是true,但开发者可以将其切换为false以关闭控件的功能(这在生产环境中非常有用,当所有bug都已修复时,可以减少HTTP请求的大小)。
如果开发者的应用程序中有母版页,他可以将控件添加到母版页。如果开发者有页面或母版页的层次结构,他可以在运行时将控件添加到层次结构的开始。
以下代码描述了如何使用控件:
<%@ 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();
}
}
步骤2:控件注册将在客户端OnSubmit事件上执行的JavaScript处理程序,并注册将包含传输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:开发者可以根据自己的喜好使用传入的信息。
以下将找到控件使用的示例:
图1. 第一个示例网页的截图 图2. 使用HtmlSourceTransmitter获取的第一个示例页面的视图 图3. 第二个示例网页的截图 图4. 使用HtmlSourceTransmitter获取的第二个示例页面的视图 可以比较截图和视图 - 它们几乎相同!
谁可以使用它? 在看来,几乎所有用户都是一样的 - 他们都是健忘的。在这种情况下,拥有异常发生前页面的“截图”非常有用。这个控件对于需要捕获服务器bug的开发者非常有用,当用户无法详细描述bug发生前的情况时。 几乎都经历过描述的情况,这个控件可以帮助解决问题!
已知问题: HtmlSourceTransmitter与Microsoft IE WebControls库中的TabStrip控件配合使用效果不佳。 这个控件只存储显示页面的HTML代码,不存储外部资源 - 图像、脚本、级联样式等。因此,开发者应该在应用程序文件夹中创建一个HTML文件,以获得最佳结果。 使用HtmlSourceTransmitter获取的页面布局可能与原始布局不同。 相信还有其他需要修改的地方,或者需要添加的其他功能。所以,请告诉。