65.9K
CodeProject 正在变化。 阅读更多。
Home

避免 IE 中的 ActiveX 激活

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (13投票s)

2006年6月2日

CPOL

4分钟阅读

viewsIcon

79981

downloadIcon

522

Dundas Software 发布了 AutoActivateControl 类的更新版本。

引言

由于 Eolas 专利,Microsoft 更改了 Internet Explorer 加载 ActiveX 控件的方式。现在,嵌入在页面中的所有交互式控件都必须在可使用之前进行激活。

ActiveX activation in Internet Explorer

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"属性,否则无法使用 HTML OBJECT标签。
  • 渲染的 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>标签。

使用控件

  1. 使用提供的文件之一编译该控件:
    • build_VS2003.bat用于 .NET 1.1;
    • build_VS2005.bat用于 .NET 2.0;
    • AutoActivateControl_VS2005.csproj用于 Visual Studio 2005;
  2. 将程序集添加到您的bin文件夹;
  3. [.NET 1.1]将 JavaScript 文件复制到您的应用程序根目录;
  4. 注册控件的标签前缀。
    <%@ Register
        TagPrefix="tri"
        Namespace="Trinet.Web.Utilities"
        Assembly="Trinet.Web.Utilities.AutoActivateControl"
    %>
  5. 将控件添加为要定位的任何控件的父级。
    <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属性中的拼写错误;
    • 添加了指向替代解决方案的链接;
© . All rights reserved.