避免 IE 中的 ActiveX 激活






4.67/5 (13投票s)
Dundas Software 发布了 AutoActivateControl 类的更新版本。
引言
由于 Eolas 专利,Microsoft 更改了 Internet Explorer 加载 ActiveX 控件的方式。现在,嵌入在页面中的所有交互式控件都必须在可使用之前进行激活。
MSDN 上的一篇文章[^] 提供了有关此更改的解决方法的说明。该解决方法涉及为每个控件实例创建一个外部脚本文件,这在动态网站中可能并不实用。
Dundas Software 的 Terrence Sheflin 最近发布了一篇文章[^]和一个控件,试图使该解决方法更具可重用性。然而,该控件存在一些问题:
该控件为创建的每个实例创建一个新的 JavaScript 文件。
- 当页面上有多个实例时,只有最后一个控件会被渲染。
- 当有多个请求时,一个请求的数据可能会被另一个请求的数据覆盖。如果控件包含敏感信息,这可能导致安全问题。
- 必须修改 Web 服务器上的安全设置,以允许 ASP.NET 在应用程序的根文件夹中创建文件。
该控件会修改页面流。
例如,如果该控件应用于TargetControl
,则包含以下内容的页面:
<form runat="server">
<h1>Page Heading</h1>
<div class="container">
<xyz:someControl id="TargetControl" runat="server" ... />
</div>
</form>
实际上将被渲染为:
<form runat="server">
<script src="/embed.js"></script> <-- This line renders TargetControl
<h1>Page Heading</h1>
<div class="container">
</div>
</form>
该控件不能声明式使用。
该控件不公开无参数构造函数,因此不能声明式使用。相反,Page_Load
方法中的代码必须找到目标控件并创建一个AutoActivateControl
实例来包装它。如果目标控件位于模板化父级(如Repeater
)内,则这涉及到为创建的每个模板实例调用FindControl
。
其他问题
- 如果脚本被禁用,将不会显示任何内容。
- 除非
OBJECT
标签具有runat="server"
属性,否则无法使用 HTMLOBJECT
标签。 - 渲染的 JavaScript 输出未正确转义 - 只替换了回车符和换行符。
- 该控件未使用当前浏览器的正确
HtmlTextWriter
类型。 - 该控件会影响所有浏览器,而不仅仅是 Internet Explorer。
更好的方法...
Internet Explorer 实际上不需要为每个控件实例生成唯一的外部 JavaScript 文件。相反,您可以创建一个带有单个方法的外部 JavaScript 文件:
window.AutoActivateControl_WriteObjectElement =
function(elementData)
{
if ("string" != typeof(elementData) || 0 == elementData.length) return;
document.write(elementData);
};
然后,您可以从页面内的脚本调用此方法,控件将无需激活即可渲染。
原始控件使用PreRender
事件捕获目标控件的输出,并使用RegisterClientScriptBlock
方法将输出包含在页面中。因此,该控件在打开的<form runat="server">
标签之后立即渲染,这超出了正常的页面流。
解决方案是创建一个容器控件,该控件将包含所有要修改的控件。然后,它可以调用RenderChildren
方法来捕获输出,并重写Render
方法以在正确的位置渲染输出。使用此解决方案,甚至静态 HTML 也可以被定位,因此<OBJECT>
标签不再需要runat="server"
属性。
新控件设计为声明式使用,并且可以在页面上的任何位置使用。它只会影响支持 ActiveX 控件的浏览器(通过HttpBrowserCapabilities
类检测),并为脚本禁用情况渲染<noscript>
标签。
使用控件
- 使用提供的文件之一编译该控件:
build_VS2003.bat
用于 .NET 1.1;build_VS2005.bat
用于 .NET 2.0;AutoActivateControl_VS2005.csproj
用于 Visual Studio 2005;
- 将程序集添加到您的bin文件夹;
- [.NET 1.1]将 JavaScript 文件复制到您的应用程序根目录;
- 注册控件的标签前缀。
<%@ Register TagPrefix="tri" Namespace="Trinet.Web.Utilities" Assembly="Trinet.Web.Utilities.AutoActivateControl" %>
- 将控件添加为要定位的任何控件的父级。
<tri:autoActivateControl runat="server"> <xyz:someControl id="TargetControl" runat="server" ... /> <object classid="clsid: ... /> </tri:autoActivateControl>
在 .NET 2.0 中,脚本将从嵌入式资源加载,因此无需分发 JavaScript 文件。如果您想覆盖此行为,可以将UseScriptResource
设置为false
。
如果您想将 JavaScript 文件移到其他位置,则需要将ScriptLocation
属性设置为新路径。
<tri:autoActivateControl runat="server"
scriptLocation="~/scripts/AutoActivateControl.js">
替代解决方案
正如 Mark Werner 和 FunkyMonkey 所指出的,还可以通过从外部脚本文件修改 HTML DOM [^] 来避免控件激活,这些操作将在页面加载后进行。此方法适用于所有页面,不仅仅是 ASP.NET,并且只需要在每个页面添加一行代码。
历史
- 2006 年 6 月 1 日 - 初始版本。
- 2006 年 6 月 6 日
- 修复了AssemblyInfo.cs文件中
TagPrefix
属性中的拼写错误; - 修复了
<%@ Register ...
指令的Assembly
属性中的拼写错误; - 添加了指向替代解决方案的链接;
- 修复了AssemblyInfo.cs文件中