开发和使用自定义服务器控件

此演练演示如何创建和编译自定义 ASP.NET 服务器控件以及如何在页中使用该控件。

通过此演练,您将学会如何执行以下任务:

  • 创建一个 ASP.NET 服务器控件。

  • 向该控件及其成员添加元数据以控制安全性和设计时行为。

  • 使用 ASP.NET 网站中的 App_Code 目录对控件进行测试(无需手动编译步骤)。

  • 在配置文件和该控件的程序集中指定一个标记前缀。

  • 将该控件编译为一个程序集并将其添加到 Bin 目录中。

  • 将一个位图嵌入到该控件的程序集中,以作为可视化设计器的工具箱图标使用。

  • 在页中使用已编译的控件。

可视化设计工具(如 Microsoft Visual Studio 2005)可以简化控件的开发过程,但并不是创建或生成自定义控件的必不可少的工具。可以通过使用任何文本编辑器创建控件,并使用属于 .NET Framework SDK 一部分的编译器从命令行生成这些控件。无论以何种方式创建控件,在可视化设计器中控件的设计时外观和行为都将相同。页开发人员可将控件添加到可视化设计器的工具箱,可将其拖动到设计图面上,还可以在属性浏览器中访问其属性和事件。在有些可视化设计器(如 Visual Studio 2005)中,自定义控件还可自行支持 IntelliSense。

要创建的控件 WelcomeLabel 是一个简单控件,与标准的 Label 控件类似。WelcomeLabel 类从 WebControl 派生,它定义了一个 Text 属性,该属性允许页开发人员提供一个文本字符串,以欢迎访问站点的用户。如果用户名出现在用户浏览器发送的标题中,WelcomeLabel 就会将用户名追加到该文本字符串。有关检索用户名的更多信息,请参见 User。例如,如果页开发人员将“Hello”设置为 Text 属性的值,则根据标题中是否出现用户名,WelcomeLabel 将呈现“Hello, 用户名!”或“Hello!”。

创建自定义服务器控件的代码

  1. 创建一个名为 WelcomeLabel.cs 的文件。

  2. 将以下代码添加到控件的源文件中:

    // WelcomeLabel.cs
        
        using System;
        
    using System.ComponentModel;
        
    using System.Security.Permissions;
        
    using System.Web;
        
    using System.Web.UI;
        
    using System.Web.UI.WebControls;
        
    namespace Samples.AspNet.CS.Controls
        {
        [
        AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
        AspNetHostingPermission(SecurityAction.InheritanceDemand,
        Level=AspNetHostingPermissionLevel.Minimal),
        DefaultProperty("Text"),
        ToolboxData("<{0}:WelcomeLabel runat=\"server\"> </{0}:WelcomeLabel>")
        ]
        
    public class WelcomeLabel : WebControl
        {
        [
        Bindable(true),
        Category("Appearance"),
        DefaultValue(""),
        Description("The welcome message text."),
        Localizable(true)
        ]
        
    public virtual string Text
        {
        
    get
        {
        
    string s = (string)ViewState["Text"];
        
    return (s == null? String.Empty : s;
        }
        
    set
        {
        ViewState["Text"= value;
        }
        }
        
    protected override void RenderContents(HtmlTextWriter writer)
        {
        writer.WriteEncodedText(Text);
        
    if (Context != null)
        {
        
    string s = Context.User.Identity.Name;
        
    if (s != null && s != String.Empty)
        {
        
    string[] split = s.Split('\\');
        
    int n = split.Length - 1;
        
    if (split[n] != String.Empty)
        {
        writer.Write("");
        writer.Write(split[n]);
        }
        }
        }
        writer.Write("!");
        }
        }
        }
        
    代码讨论

下面的代码讨论并不是执行此演练中的步骤必不可少的内容,可以在开始时跳过。但是,如果您初学控件创作,我们建议您至少要在完成演练后阅读此内容。

如果控件要呈现用户界面 (UI) 元素或任何其他客户端可见的元素,则应从 System.Web.UI.WebControls.WebControl(或派生类)派生该控件。如果控件要呈现在客户端浏览器中不可见的元素(如隐藏元素或 meta 元素),则应从 System.Web.UI.Control 派生该控件。WebControl 类从 Control 派生,并添加了与样式相关的属性,如 FontForeColorBackColor。此外,一个从 WebControl 派生的控件也自行参与到 ASP.NET 的主题功能。

如果您的控件要扩展现有控件(如 ButtonLabelImage 控件)的功能,则可以从该控件派生。由于 WelcomeLabel 扩展了 Label 控件的功能,因此它可从 Label 派生。但是,本演练从 WebControl 派生 WelcomeLabel 以演示如何定义属性和定义属性元数据。

WelcomeLabel 定义一个 Text 属性,并使用视图状态存储该属性值。使用视图状态保存回发间的 Text 值。每次回发时,将重新创建页并从视图状态还原值。如果 Text 值并未存储在视图状态中,则在每次回发时会将值设置为其默认的 EmptyViewState 属性继承自 WebControl,是保存数据值的字典。通过使用 String 键,可输入和检索值。本例中将“Text”用作键。字典中的项被类型化为 Object,然后必须将其强制转换为属性类型。有关更多信息,请参见 ASP.NET 状态管理概述

WelcomeLabel 控件通过重写继承的 RenderContents 方法呈现其 Text 属性。传入 RenderContents 方法的参数是 HtmlTextWriter 类型的对象,是具有呈现标记和其他 HTML(和 HTML 变量)标记的方法的实用工具类。

注意,WelcomeLabel 会连续调用 HtmlTextWriter 对象的 Write 方法,而不是先执行字符串串联然后调用 Write 方法。由于 HtmlTextWriter 对象直接写入输出流,因此这样可以提高性能。字符串串联需要时间和内存来创建字符串,然后写入流。在控件中实现呈现时,应按照本演练中说明的模式进行操作。

注意

通常,在从 WebControl 派生控件并呈现单个元素时,应重写 RenderContents 方法(而不是 Render 方法),以呈现控件标记中的内容。在呈现控件及其样式属性的开始标记之后,WebControlRender 方法将调用 RenderContents。如果重写 Render 方法以写入内容,则控件将丢失生成到 WebControlRender 方法中的样式呈现逻辑。有关呈现从 WebControl 派生的控件的更多信息,请参见 Web 控件呈现示例

应用于 WelcomeLabel 的属性包含由公共语言运行库和设计时工具使用的元数据。

在类级别上,通过以下属性标记 WelcomeLabel

  • AspNetHostingPermissionAttribute 是代码访问安全属性。该属性使 JIT 编译器检查链接到 WelcomeLabel 的代码是否具有 AspNetHostingPermission 权限。所有的公共 ASP.NET 类均使用此属性标记。应将 AspNetHostingPermissionAttribute 应用于控件,以对部分受信任的被调用方进行安全检查。

  • DefaultPropertyAttribute 是设计时属性 (Attribute),它指定控件的默认属性 (Property)。在可视化设计器中,当页开发人员在设计图面上单击控件时,属性浏览器通常突出显示此默认属性。

  • ToolboxDataAttribute 指定元素的格式字符串。如果在工具箱中双击控件或将其从工具箱拖动到设计图面上时,该字符串将成为控件的标记。对于 WelcomeLabel,该字符串创建此元素:

        
    <aspSample:WelcomeLabel runat="server"> </aspSample:WelcomeLabel>

WelcomeLabel 控件还从 WebControl 基类继承了两个属性:ParseChildrenAttributePersistChildrenAttribute。它们被应用为 ParseChildren(true)PersistChildren(false)。这两个属性 (Attribute) 一起与 ToolboxDataAttribute 属性 (Attribute) 共同使用,这样可将子元素解释为属性 (Property),并将属性 (Property) 作为属性 (Attribute) 保留。

以下应用于 WelcomeLabelText 属性 (Property) 的属性 (Attribute) 是标准设计时属性 (Attribute),通常会将标准设计时属性 (Attribute) 应用于控件的所有公共属性 (Property):

  • BindableAttribute(被指定为 truefalse),指定将属性绑定到数据对可视化设计器是否有意义。例如,在 Visual Studio 2005 中,如果属性标记为 Bindable(true),则该属性可显示在“数据绑定”对话框中。如果属性 (Property) 没有使用此属性 (Attribute) 标记,则属性 (Property) 浏览器会推断其值为 Bindable(false)

  • CategoryAttribute 指定如何在可视化设计器的属性浏览器中对属性进行分类。例如,当页开发人员使用属性浏览器的分类视图时,Category("Appearance") 将告知属性浏览器在“外观”类别中显示属性。可以根据属性浏览器中的现有类别指定字符串参数,也可以创建自己的类别。

  • DescriptionAttribute 指定属性的简短描述。在 Visual Studio 2005 中,属性浏览器将在“属性”窗口底部显示选定的属性的描述。

  • DefaultValueAttribute 指定属性的默认值。此值应与从属性访问器 (getter) 返回的默认值相同。在 Visual Studio 2005 中,DefaultValueAttribute 允许页开发人员通过在“属性”窗口中唤出快捷菜单然后单击“重置”按钮将属性值重置为其默认值。

  • LocalizableAttribute(指定为 truefalse)指定本地化属性对可视化设计器是否有意义。当某属性标记为 Localizable(true) 时,可视化设计器会在对本地化资源进行序列化时包含该属性。对控件轮询可本地化的属性时,设计器会将此属性值保存到非特定于区域性的资源文件或其他本地化源中。

    注意

    由于 ASP.NET 1.0 版和 1.1 版中的 ASP.NET 本地化模型不同,因此在这些版本中不能将 LocalizableAttribute 应用于自定义服务器控件。

应用于控件及其成员的设计时属性在运行时不会影响控件的功能,但在可视化设计器中使用控件时,这些属性能提升开发人员的体验。有关服务器控件的设计时、分析时和运行时属性的完整列表,可参见自定义服务器控件的元数据属性

注意

App_Code 目录是 ASP.NET 1.0 和 1.1 中都没有的新功能。使用 App_Code 目录进行初始控件测试是一个可选步骤。生成服务器控件的主要步骤与早期版本相同,下一节“将控件编译为程序集”将对此进行介绍。

创建 ASP.NET 网站和 App_Code 目录

  1. 创建一个名为 ServerControlsTest 的网站。可以在 IIS 中将该站点创建为名为 ServerControlsTest 的虚拟目录。有关创建和配置 IIS 虚拟目录的详细信息,请参见如何:在 IIS 中创建和配置虚拟目录

  2. 直接在网站根目录(也称 Web 应用程序根目录)下创建一个 App_Code 目录。

  3. 将控件的源文件(WelcomeLabel.cs 或 WelcomeLabel.vb)复制到 App_Code 目录。

创建标记前缀

标记前缀是指在页中以声明方式创建控件时出现在控件类型名称前面的前缀,如 <asp:Table /> 中的“asp”。若要在页中以声明方式使用您的控件,则 ASP.NET 需要一个映射到该控件的命名空间的标记前缀。通过在每个使用自定义控件的页上添加一个 @ Register 指令,页开发人员可提供标记前缀/命名空间映射,如下面的示例所示:

<%@ Register TagPrefix="aspSample"
Namespace="Samples.AspNet.CS.Controls"%>
注意

ASP.NET 2.0 中的 @ Register 指令与 ASP.NET 1.0 和 ASP.NET 1.1 中的相同。如果您熟悉 ASP.NET 早期版本中的 Register 指令,您会注意到前面的 Register 指令中缺少指定控件程序集名称的 assembly 属性。如果缺少 assembly 属性,则 ASP.NET 会推断该程序集是从 App_Code 目录中的源文件动态编译而来。

除了在每个 .aspx 页中使用 @ Register 指令,页开发人员还可以在 Web.config 文件中指定标记前缀/命名空间映射。如果将在 Web 应用程序的多个页中使用自定义控件,则该方法非常有用。下面的过程描述如何在 Web.config 文件中指定标记前缀映射。

在 Web.config 文件中添加标记前缀映射

  1. 如果不存在名为 Web.config 的文本文件,则请在网站的根目录下创建该文件。

  2. 创建了新的(空的)Web.config 文件之后,将以下代码复制到该文件中并保存该文件。

    <?xml version="1.0"?>
        
    <configuration>
        
    <system.web>
        
    <pages>
        
    <controls>
               
    <add tagPrefix="aspSample"   
                 namespace="Samples.AspNet.CS.Controls">
               
    </add>
        
    </controls>
        
    </pages>
        
    </system.web>
        
    </configuration>
     
    突出显示部分是一个标记前缀项,该项将标记前缀“aspSample”映射到命名空间 Samples.AspNet.CS.ControlsSamples.AspNet.VB.Controls
  3. 如果已存在一个 Web.config 文件,则请将前一步骤中突出显示的文本作为该配置文件的 controls 元素的子项添加到该文件中。如果 Web.config 文件中没有 controlspages 元素,则请按照前一步骤中介绍的方法创建这些元素。

    注意

    标记前缀项必须是 controls 节的子项,而该节必须位于 pages 节下,而后者又必须是 system.web 的子项。

在配置文件中指定了标记前缀映射之后,可以在网站的任何页中以声明方式使用 WelcomeLabel 控件(如 <aspSample:WelcomeLabel />)。

注意

标记前缀的配置项是 ASP.NET 2.0 的新功能。在 ASP.NET 1.0 和 1.1 中,标记前缀映射在每个使用自定义控件的页的 @ Register 指令中指定。

创建使用控件的页

创建使用自定义控件的页

  1. 在网站中创建一个名为 WelcomeLabelTest.aspx 的文本文件。

  2. 将以下标记复制到 WelcomeLabelTest.aspx 文件中并保存该文件。

        
    <%@ Page Language="C#"%>
        
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        
    <html  >
        
    <head id="Head1" runat="server">
        
    <title>WelcomeLabel Test</title>
        
    </head>
        
    <body>
        
    <form id="form1" runat="server">
        
    <div>
        
    <aspSample:WelcomeLabel Text="Hello" ID="WelcomeLabel1"
        runat="server" BackColor="Wheat" ForeColor="SaddleBrown" />
        
    </div>
        
    </form>
        
    </body>
        
    </html>
  3. 在地址栏中输入以下 URL,以在浏览器中显示 WelcomeLabelTest.aspx:

    http://localhost/ServerControlsTest/WelcomeLabelTest.aspx
  4. 对控件的源代码做一些更改。例如,通过在 RenderContents 方法末尾处添加此行代码来多写一个字符串:

        
    writer.Write("Testing how the App_Code directory works.");
  5. 在浏览器中刷新 WelcomeLabelTest.aspx 页。

    将看到,尽管没有编译控件,对控件所做的更改仍在页中反映出来了。

除了显式定义的 WelcomeLabel 控件的 Text 属性之外,从页中的控件实例可以看到,它还具有之前并没有定义的 BackColorForeColor 属性。WelcomeLabel 控件通过从 WebControl 基类继承,从而获取与样式相关的这些属性和其他属性。此外,WelcomeLabel 可自行分配外观并成为主题的一部分。

尽管利用 App_Code 目录可以不编译就对控件进行测试,但是如果您希望将您的控件作为对象代码分发给其他开发人员,则必须对其进行编译。此外,如果没有将控件编译为程序集,就不能将该控件添加到可视化设计器的工具箱中。

将控件编译为程序集

  1. 按照以下这些步骤设置计算机的 Windows 环境 PATH 变量,使其包含 .NET Framework 的安装路径:

    1. 在 Windows 中,右击“我的电脑”,选择“属性”,单击“高级”选项卡,然后单击“环境变量”按钮。

    2. 在“系统变量”列表中,双击 Path 变量。

    3. 在“变量值”文本框中,将一个分号 (;) 添加到文本框中的现有值的末尾,然后键入 .NET Framework 的安装路径。.NET Framework 通常安装在位于 \Microsoft.NET\Framework\版本号 的 Windows 安装目录中。

    4. 单击“确定”关闭每个对话框。

  2. 从为本演练第一步中的源文件创建的目录中运行以下命令。

    注意

    这与复制控件源文件以进行测试的 App_Code 目录不同。

    csc /t:library /out:Samples.AspNet.CS.Controls.dll /r:System.dll /r:System.Web.dll *.cs
        

     

    /t:library 编译器选项告知编译器创建一个库,而不是创建一个可执行程序集。/out 选项为程序集提供名称,而 /r 选项则列出链接到您的程序集的那些程序集。

为保持示例独立,本演练要求创建具有单个控件的程序集。通常,.NET Framework 设计指导原则建议不要创建只包含很少的类的程序集。为了便于部署,应尽可能少地创建程序集。

在控件程序集中嵌入图标

可视化设计器(如 Visual Studio 2005)通常使用默认图标(如齿轮图像)显示工具箱中的控件。作为控件的一个选项,可以通过在控件的程序集中嵌入一个 16*16 像素的位图来自定义控件在工具箱中的外观。根据约定,可视化设计器将该位图最下方左侧的像素用作透明色。

在控件程序集中嵌入图标

  1. 创建或获取一个 16*16 像素的位图,将其作为控件的工具箱图标。

  2. 将该位图命名为 WelcomeLabel.bmp。

  3. 将该位图文件添加到包含 WelcomeLabel 控件源文件的目录(CustomControlsCS 或 CustomControlsVB)中。

  4. 从包含源文件的目录中运行以下命令:

    csc /res:WelcomeLabel.bmp,Samples.AspNet.CS.Controls.WelcomeLabel.bmp
        /t:library /out:Samples.AspNet.CS.Controls.dll /r:System.dll
        /r:System.Web.dll *.cs

    此命令将编译控件并将该位图作为资源嵌入到程序集中。嵌入的位图资源的名称必须与关联控件的命名空间限定名称完全相同。例如,如果控件名称为 Samples.AspNet.CS.Controls.WelcomeLabel,则嵌入的位图的名称必须为 Samples.AspNet.CS.Controls.WelcomeLabel.bmp。此命名约定使可视化设计器能自动将该位图用作控件的工具箱图标。如果不使用此命名约定,则必须将 ToolboxBitmapAttribute 应用于该控件,以指定嵌入的位图资源的名称。

使用 TagPrefixAttribute 提供标记前缀/命名空间映射

在本演练前面的内容中,在介绍使用 App_Code 目录时讲述了页开发人员如何在页或 Web.config 文件中指定标记前缀。可以选择通过包含程序集级别的 System.Web.UI.TagPrefixAttribute 属性,建议可视化设计器应为控件使用的默认标记前缀。如果设计器未找到在 Web.config 文件或页中的 Register 指令中映射的标记前缀,TagPrefixAttribute 属性就会为可视化设计器提供可以使用的标记前缀,因此该属性非常有用。在工具箱中首次双击控件或将其从工具箱拖动到页中时,此标记前缀将向页进行注册。

如果决定使用 TagPrefixAttribute 属性,则可以在与控件一起编译的单独文件中指定该属性。根据约定,该文件名为 AssemblyInfo.语言扩展,如 AssemblyInfo.cs 或 AssembyInfo.vb。下面的过程介绍如何指定 TagPrefixAttribute 元数据。

注意

如果没有在控件的程序集中指定 TagPrefixAttribute,并且页开发人员没有在页或 Web.config 文件中指定标记前缀/命名空间映射,则可视化设计器将创建一个默认的标记前缀。例如,从工具箱中拖动控件时,Visual Studio 2005 将创建其自己的控件标记,如 cc1

使用 TagPrefixAttribute 添加命名空间/标记前缀映射

  1. 在源代码目录中创建一个名为 AssemblyInfo.cs 或 AssemblyInfo.vb 的文件并向该文件添加以下代码。

        
    using System;
        
    using System.Web.UI;
        [assembly: TagPrefix("Samples.AspNet.CS.Controls""aspSample")]
    标记前缀属性在命名空间 Samples.AspNet.CS.Controls 与前缀 aspSample 之间创建映射。
  2. 使用前面使用的编译命令重新编译所有的源文件(使用或不使用嵌入资源)。

若要测试自定义控件的已编译版本,则必须使网站中的页可以访问此控件的程序集。

使网站可以访问控件的程序集

  1. 在网站的根目录下创建一个 Bin 目录。

  2. 将控件程序集(Samples.AspNet.CS.Controls.dll )复制到 Bin 目录。

  3. 从 App_Code 目录中删除该控件的源文件。

    如果没有删除源文件,则您的控件的类型将同时存在于编译的程序集中和由 ASP.NET 动态生成的程序集中。这在加载该控件时会造成不明确引用,加载任何使用该控件的页时将生成编译器错误。

本演练中创建的程序集必须放在 ASP.NET 网站的 Bin 目录中才能使网站中的页使用您的控件,故而该程序集为私有程序集。如果其他应用程序没有安装该程序集的副本,则这些应用程序都不能访问该程序集。如果要为共享的 Web 宿主应用程序创建控件,通常会将控件打包到一个私有程序集中。但是,如果要创建在专用宿主环境中使用的控件,或要创建 ISP 向所有客户提供的一系列控件,则需要将您的控件打包到安装在全局程序集缓存中的一个共享(强名称)程序集中。有关更多信息,请参见使用程序集和全局程序集缓存

接下来,必须修改在 Web.config 中创建的标记前缀映射,以指定控件的程序集名称。

修改 Web.config 中的标记前缀映射

  • 编辑 Web.config 文件,向 add tagPrefix 元素添加 assembly 属性:

    <controls>
        
    <add tagPrefix="aspSample"
        namespace="Samples.AspNet.CS.Controls"
        assembly="Samples.AspNet.CS.Controls">
        
    </add>
        
    </controls>
    assembly 属性指定控件所在的程序集的名称。add tagPrefix 元素将标记前缀映射到命名空间和程序集的组合。ASP.NET 从 App_Code 目录中的源文件动态生成程序集时,无需提供程序集属性。未使用程序集属性时,ASP.NET 会从通过 App_Code 目录动态生成的程序集加载控件的类型。

查看使用自定义控件的页

  • 通过在地址栏中输入以下 URL,可在浏览器中显示 WelcomeLabelTest.aspx 页:

    http://localhost/ServerControlsTest/WelcomeLabelTest.aspx

如果在可视化设计器(如 Visual Studio 2005)中使用您的控件,可以向工具箱添加您的控件,可以将其从工具箱拖动到设计图面,还可以在属性浏览器中访问其属性和事件。此外,在 Visual Studio 2005 中,您的控件在页设计器的“源”视图和代码编辑器中具有完整的 IntelliSense 支持。这包括 script 块中的语句结束支持以及页开发人员单击控件标记时的属性浏览器支持。

注意

在许多可视化设计器中,可以将自定义控件添加到设计器的工具箱中。有关详细信息,请参阅设计器文档。

本演练演示了如何开发简单的自定义 ASP.NET 服务器控件以及如何在页中使用该控件。您了解了如何定义属性以及如何将控件编译为程序集。有关更多信息,包括有关呈现、定义属性、维护状态和实现复合控件的信息,请参见开发自定义 ASP.NET 服务器控件

在本演练中,您了解了可以为您的控件提供自定义工具箱图标。您还学习了如何添加设计时元数据,从而为您的控件自定义属性浏览器支持。通过使用在设计时和运行时提供不同用户界面的可视化设计器类,复杂控件(如 GridView 控件)进一步增强了其设计时体验。ASP.NET 2.0 为服务器控件提供的设计器对象模型与 ASP.NET 1.0 和 1.1 中提供的模型大为不同。若要了解有关在 ASP.NET 2.0 中为您的控件实现自定义设计器类的信息,请参见 ASP.NET 控件设计器概述

在 ASP.NET 2.0 中,服务器控件通过使用适配器类可以为客户端浏览器或设备定义不同行为。有关更多信息,请参见开发 ASP.NET 服务器控件的适配器

不同的浏览器和相同浏览器的不同版本支持不同的功能。ASP.NET 服务器控件将自动确定已请求 .aspx 页的浏览器,并为该浏览器正确设置所生成的 HTML 标记的格式。但是,部分控件功能无法在较低版本的浏览器上呈现,因此需要在尽可能多的浏览器类型上查看页的输出,以确保页以预期方式呈现在所有浏览器中。有关更多信息,请参见 ASP.NET Web 服务器控件和浏览器功能.

posted @ 2009-06-18 10:46  杨子宜  阅读(359)  评论(0编辑  收藏  举报