单击此处可下载本文的代码示例
本页内容
简介 | |
使用贯穿应用程序的网页模板 | |
构建导航系统 | |
限制对应用程序各部分的访问 | |
使用个性化系统 | |
应用样式 | |
小结 |
简介
欢迎您阅读第三篇 ASP.NET Jumpstart 文章,该系列的四篇文章将从头至尾引领您创建一个完整的应用程序。该系列的第一篇文章介绍了完整的初学者工具包,向您展示如何安装和运行该应用程序。第二篇文章讨论如何构建应用程序的数据层,以及如何理解 ASP.NET 页面上的数据源控件与初学者工具包中底层数据的交互原理。第三篇文章将继续帮助您了解如何构建该应用程序的表示层 — 通过研究应用程序和网页框架(自始至终使用的)的创建过程而实现。
正在构建的初学者工具包名为 Media Share Library Starter Kit。通过它创建一个允许注册用户表示其媒体项目集合(例如,电影 DVD、音乐 CD、书籍等)的应用程序很容易,以便供其他注册用户借用。用户可以集中浏览使用该应用程序的组所持有的项目库,并向项目的注册所有者请求借用指定的项目。Media Share Library Starter Kit 的概念为您提供一个快速组织库集合的框架,以便该库集合可以在更多的人之间共享。
正如前几篇文章所阐述的那样,无论是否使用初学者工具包,它本身就说明了 ASP.NET 在这一最新的版本的 ASP.NET 2.0 中所具有的一些更为激动人心的附加功能,这正是其微妙之处。初学者工具包广泛使用母版页、新的代码隐藏模型、新服务器控件以及其他功能。但是,本文的重点是有关它使用的一些令人振奋、新的 ASP.NET 基本功能(例如,母版页的使用),以及应用程序页面中主题和导航的使用,在 ASP.NET 2.0 中可以找到这些功能。
让我们开始自己动手构建初学者工具包的框架吧,首先来使用 ASP.NET 2.0 的母版页功能。使用贯穿应用程序的网页模板
ASP.NET 2.0 加入了母版页,这是令人更为振奋的附加功能之一。母版页提供的基本功能是创建一个应用程序自始至终所使用的网页模板。大多数个体用户不会构建各自应用程序的所有页面,因为应用程序之间的差异太大了。因此,您会发现页与页之间存在很多相同的应用程序页面元素。例如,大多数页面看起来都包含一个标题、导航提要栏以及某类页脚。如果使用一个模板构建应用程序,您可以将这些公共元素放置到模板中,那么就无需在开发应用程序的每个页面时不厌其烦地将这些项目重新编写到程序中。此外,如果需要在使用模板时更改这些公共元素,那么只需更改一次,就可以一劳永逸地在整个应用程序中反映出来。
构建母版页 — MediaLibraryMain.master
这样看来,模板确实很有用,但是如何在 ASP.NET 2.0 中创建它呢?创建母版页与创建标准的 .aspx 页一样简单。您可以通过“New File”对话框来实现。Media Share Library Starter Kit 的母版页命名为 MediaLibraryMain.master(请注意这里的母版页使用 .master 代替标准的 .aspx 文件扩展名)。
MediaLibraryMain.master 页面顶部具有如程序清单 1 所示的下列页面指令。
程序清单 1. @Master 页面指令
<%@ Master Language="VB" CodeFile="MediaLibraryMain.master.vb" Inherits="MediaLibraryMain" %>
想必您也看到了,@Master 指令与 @Page 指令之间并没有太大差别。还有很多属性都是一样的。
如果浏览 Microsoft Visual Studio 中的 MediaLibraryMain.master 页,可看到如图 1 所示的“Design”视图。
图 1. 在“Design”视图中浏览媒体共享库 (Media Share Libaray) 的母版页
仔细观察该图片,您会发现媒体共享库的母版页是十分简单的。实际上,页面上只有几个控件。这些就是我们希望在应用程序所有页面上出现的控件和元素。其中有标题、导航、登录到应用程序的几个链接、一个 SiteMapDataSource 控件以及最为重要的 ContentPlaceHolder 控件。
SiteMapDataSource 控件(位于母版页底部,因此无法在图 1 中看到)只需放置在可以与 Web.sitemap 文件进行交互的页面上,该文件是应用程序所包含的文件。连接该 .sitemap 文件的 Menu 控件用于显示应用程序的导航。本文稍后将讨论该导航系统。
ContentPlaceHolder 控件位于母版页的某个特定区域,它可以声明任何继承的内容页放置页面数据和信息的位置。除了各个 ContentPlaceHolder 控件(因为可以有多个)之外,页面上包含的所有内容都认为是网页模板的一部分。
最后真正需要关注的就是母版页上的 LoginView 控件。它是绑定到应用程序成员身份和角色管理系统上的控件。LoginView 控件可以为最终用户显示几个不同的视图或多组数据。匿名用户(访问应用程序但是还没提供凭据的用户)、经过身份验证的用户(以某种方式登录到应用程序的用户),以及一些权限更高的用户(这类用户不仅通过了身份验证,还属于某个特定应用程序角色,例如管理员角色)分别有一个视图。让我们看一下 MediaLibraryMain.master 页上使用的 LoginView。程序清单 2 对此作出了说明。
程序清单 2. 浏览 LoginView 服务器控件
<asp:LoginView ID="LoginView1" runat="server"> <AnonymousTemplate> <asp:LoginStatus ID="LoginStatus1" runat="server" /> <br /> <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="Join.aspx" Text="Join Today!"></asp:HyperLink> </AnonymousTemplate> <LoggedInTemplate> <asp:LoginStatus ID="LoginStatus1" runat="server" /> </LoggedInTemplate> </asp:LoginView>
在本例中,匿名用户和已经登录到应用程序的用户分别有一个视图。这两个视图唯一的差别就在于是否存在指向 Join.aspx 页的超链接,该链接是显示给匿名用户的,单击这些链接就可以根据兴趣加入应用程序。除此之外,两个视图都会显示一个 LoginStatus 控件,该控件将为匿名用户显示一个登录超链接,而为已经登录的用户显示一个注销超链接。下一步,我们将介绍如何使用该母版页。
继承母版页 — 创建内容页
虽然母版页已准备就绪,但它不能在浏览器中调用。使用母版页的意图是利用其中定义的网页模板创建一个内容页。
为了完成这项任务,首先要创建在应用程序根目录中可见的 Default.aspx 页。在 Visual Studio 中,右键单击解决方案资源管理器中的项目,选择所供菜单中的 Add New Item。此操作将启动“添加新项目”对话框。选择该对话框中的 Web Form。然后,您将看到用于创建该页面的若干选项。该对话框如图 2 所示。
图 2. 构建一个内容页
在该对话框中,要选择的比较重要的两个项目有:是否将业务逻辑放在代码隐藏文件 (Default.aspx.vb) 中,以及是否使用母版页。Media Share Library Starter Kit 在整个应用程序使用过程中都要利用代码隐藏文件,不过,所有业务逻辑代码都可以轻松地内嵌在构建的初学者工具包中。
如果要将 Default.aspx 页转变为内容页,必须确保选中了对话框中的 Select master page 选项。执行该操作后,会出现一个新的对话框,该对话框允许您选择要使用的母版页(可在应用程序中拥有多个母版页)。图 3 显示的是后一个对话框。
图 3. 选择合适的母版页
选好母版页后,单击 OK 按钮,将创建 Default.aspx 页。在外观上,它与您或许已经习惯的标准 .aspx 页略有不同。首先,检查该内容页的 @Page 指令。如程序清单 3 所示。
程序清单 3. 内容页的 @Page 指令
<%@ Page Language="VB" MasterPageFile="~/MediaLibraryMain.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" Title="Media Share Library" Theme="Evjen" %>
该指令看起来相当标准,唯一可辨别的差异是该内容页使用 MasterPageFile 属性。属性值必须指向您希望使用的母版页位置。
除此之外,另一个需要注意的重要属性是 Title 属性。在母版页所包含的 <title> HTML 元素之间的确可以声明页面的标题目录,但是通过 Title 属性在 @Page 指令中直接定义页面标题还可以覆盖之前的设置。
最后要讨论的属性是 Theme 属性,它与母版页无关。ASP.NET 2.0 网页可以并入一个称为主题 的中央托管类型系统。该属性仅指向为生成该页而引用的主题名。本文稍后将讨论主题这一内容。
真正将该 Default.aspx 页转变为内容页的项目,除了 @Page 指令之外还有 @Page 指令声明后面可见的所有内容。程序清单 4 显示该内容。
程序清单 4. 内容页的其余部分
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <fieldset> Welcome to the Media Share Library </fieldset> </asp:Content>
母版页上每包含一个 ContentPlaceHolder 服务器控件,在继承母版页的 ASP.NET 页面上就应该有一个对应的 Content 服务器控件,但这不是必须的。举例来说,如果 MediaLibraryMain.master 页上有一个 ContentPlaceHolder 控件(其 ID 是 ContentPlaceHolder1),那么为了在定义的此区域中放置内容,使用该母版页的所有页面都需要加入一个指向该 ContentPlaceHolder 控件的 Content 服务器控件。
Default.aspx 正是由于该原因而使用了该母版页:您会发现页面上包含程序清单 4 所示的 Content 控件。该控件的一个重要属性是 ContentPlaceHolderID 属性,它指向母版页上所使用的 ContentPlaceHolder 控件的 ID 值(仍然是 ContentPlaceHolder1)。
在页面上设置好 Content 控件后,只需将所有希望在母版页定义区域中出现的服务器控件或 HTML 放在 Content 控件的开头和结尾元素之间即可。不允许将服务器控件或 HTML 元素放在该控件的外部,这将导致页面引发一个错误。
还要记住,不要将开头和结尾 HTML 页面元素放在您使用的 Content 控件中,因为这些元素在母版页中已经进行了定义(例如 <html>、<head> 和 <body> 等元素)。构建导航系统
要构建 Media Share Library Starter Kit 的应用程序框架,下一步是构建应用程序的导航系统。正如上文针对初学者工具包中母版页的使用所讨论的那样,将 Menu 服务器控件绑定到应用程序的导航系统是为了能够显示给最终用户。图 4 显示绑定到导航系统后的 Menu 控件。
图 4. 绑定到应用程序导航系统的“Menu”服务器控件
那么,该信息存储在什么位置呢?这个问题问得好,事实上激动人心的部分就在于此!ASP.NET 2.0 为您提供了一种在中央位置存储整个应用程序导航信息的方法。在此之前,许多 Web 开发人员会将导航结构放在应用程序的各个页面上,通常的做法就是将导航代码从一个页面复制-粘贴到另一个页面上。您应该可以想象,在这种情况下如果要创建一个大型 Web 应用程序的导航系统,将需要多大规模的更改!同样,不难想象这样的应用程序在实际应用中又是多么容易出现问题!
如果开发人员可以集中宿主导航设置,那么在真正发生更改时,只需在一个位置作出修改,就可以立即在使用该系统应用程序的每个页面上反映出来。
Media Share Library Starter Kit 确实利用了 ASP.NET 2.0 站点导航系统。默认情况下,这都是由 XML 文件 Web.sitemap 驱动的。程序清单 5 对此文件作出说明。
程序清单 5. 应用程序的 Web.sitemap 文件
该 XML 文件包含的内容并不多。不难看出,它非常简单。Web.sitemap 文件由 元素组成,这些元素的嵌套关系决定了应用程序的导航结构。该文档中只能定义一个根页面(本例中为主页 Default.aspx)。该主页之上的其余嵌套链接都指向主库中的网页以及为站点管理员所使用的一个网页。
创建好该 XML 文件后,就可以在应用程序中使用它了。通过在需要使用这些导航数据的页面上放置一个 SiteMapDataSource 控件就可以实现。如前文所述,在本文示例中放置该控件的唯一位置就是母版页。该初学者工具包的母版页MediaLibraryMain.master 就含有该数据源控件。将数据源控件绑定到 Web.sitemap 文件无需手动添加任何具体属性。相反,SiteMapDataSource 控件会代表您自动绑定到该 XML 文件。
设置好 SiteMapDataSource 控件后,通过 DataSourceID 属性使用 Menu 服务器控件来显示应用程序的导航系统就显得相当简单了,如程序清单 6 所示。
程序清单 6. 将“Menu”服务器控件绑定到 SiteMapDataSource 控件
<?xml version="1.0" encoding="utf-8" ?> <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"> <siteMapNode url="~/Default.aspx" title="Home" description=""> <siteMapNode url="~/Library/Default.aspx" title="Alerts & Info" description="" /> <siteMapNode url="~/Library/MainLibrary.aspx" title="Main Library" description="" /> <siteMapNode url="~/Library/MyLibrary.aspx" title="My Library" description="" /> <siteMapNode url="~/Library/EnterMedia.aspx" title="Enter New Media" description="" /> <siteMapNode url="~/Admin/Default.aspx" title="Admin" description="" /> </siteMapNode> </siteMap>
只要将页面上 SiteMapDataSource 控件(默认值是 SiteMapDataSource1)的 ID 赋值给 DataSourceID 属性,就可以将该控件与 SiteMapDataSource 控件所提供的结果绑定到一起。
限制对应用程序各部分的访问
您总是想要构建具有受限访问点的 Web 应用程序。该初学者工具包与这样的应用程序毫无差别。“Library”文件夹的所有内容只能供注册用户查看和使用。同样,“Admin”文件夹的内容则只能供加入管理员角色的注册用户所使用。
ASP.NET 2.0 包含的成员身份和角色管理系统可以胜任这些任务。这些系统可以管理应用程序的身份验证/授权过程,而且允许您将特定用户设置为自定义的角色。
下面,我们来了解如何设置一个管理这些任务的系统。
嵌套的 Web.config 文件
要建立这种类型的系统,首先要做的是在您的应用程序中放入一个正确的 Web.config 文件。将该文件放在应用程序的根部可以控制许多具有不同特征的应用程序行为,这一点您可能再清楚不过了。
相对来说,这一点不假,但是事实上 Web.config 文件是一个覆盖文件,它实际上用于覆盖建立好的设置和行为,在服务器的 machine.config 文件中已经对其进行了设置。machine.config 文件控制着服务器内驻留的每个单独应用程序的设置和行为。要覆盖该文件中保存的设置,只要在应用程序的根部放置一个 Web.config 文件即可。这样做允许您在该文件中加入更多特定于应用程序的设置。
然而,在 Media Share Library Starter Kit 中,需要应用仅特定于某个应用程序具体目录的设置。实际上这样的设置有两处 — 一是“Library”目录,另一处是“Admin”目录。我们先来了解针对该初学者工具包不同目录的特殊规则,然后再来了解如何应用这些设置:
• |
根目录中只包含一个 Web.config 文件,该文件为访问此站点的匿名用户提供了开放式的访问。此处建立的规则将级联到应用程序的其他各级子目录,只要目录内驻留的 Web.config 文件没有明确地覆盖这些规则,就一直有效。 |
• |
初学者工具包的“Library”目录中有一个 Web.config 文件,该文件对其中包含的每个文件和目录应用指定的设置。该库目录内容仅供经过身份验证的用户使用,与用户可能的角色无关,这里只关心用户是否进行了身份验证。 |
• |
初学者工具包的“Admin”目录也包含一个 Web.config 文件,该文件同样会对其中包含的每个文件和目录应用指定的设置。该目录内容的使用者仅限于那些通过身份验证而且加入管理员角色的用户。管理员角色是一个自定义角色。 |
因此,切记虽然应用程序可以在根目录中包含 Web.config 文件,但是在想要操作的子目录中放置额外的 Web.config 文件就可以覆盖应用到应用程序级别的那些设置。在图 5 中对此进行解释。
图 5. 对应用程序特定目录实施精确的控制
应用根目录所需的设置
在启动并运行 Media Share Library Starter Kit 的成员身份和角色管理系统之前,首先来了解应用程序根目录中包含的 Web.config 文件所使用的设置。
默认的成员身份提供程序可以控制应用程序中运行的成员身份系统,但是根 Web.config 文件也很容易将该提供程序覆盖。默认的成员身份提供程序 SqlMembershipProvider 控制着创建用户以及登录应用程序的方式。默认的成员身份提供程序具备许多方面的功能,但就本文示例应用程序而言,我决定覆盖用户所需的强密码功能,以便使登录过程变得更简单。虽然这样做会降低安全性,但是我的想法是使最终用户能够使用容易记忆的密码。程序清单 7 说明如何重新限定 ASP.NET 中的 SqlMembershipProvider。
程序清单 7. 重新建立 SqlMembershipProvider
<membership> <providers> <clear/> <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalSqlServer" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="3" /> </providers> </membership>
以上 Web.config 文件的代码完成了若干任务。在此程序中,第一步是清除之前的提供程序,这些提供程序可能是在任何 Web.config 父文件中声明的,也可能是 machine.config 文件包含的一部分。这一步是使用 元素完成的。
清除了程序中之前声明的提供程序后,下一步就是以我们感兴趣的方式建立 SqlMembershipProvider。这是使用 元素完成的。本示例定义 SqlMembershipProvider 所使用的属性大部分都没有超出默认的提供程序规范。
这些属性中的 name 属性定义提供程序的名称。该属性可以赋值为任何您认为应用程序需要的值。type 属性指向 SqlMembershipProvider 的实例,我们关注如何使用该提供程序。
connectionStringName 属性使用 LocalSqlServer 连接到数据库。该连接字符串名是对声明连接的引用,该连接位于程序清单 8 所示的 machine.config 文件的 部分。
程序清单 8. machine.config 文件中声明的 LocalSqlServer 连接
<connectionStrings> <add name="LocalSqlServer" connectionString="data source=./SQLEXPRESS; Integrated Security=SSPI; AttachDBFilename=|DataDirectory|aspnetdb.mdf; User Instance=true" providerName="System.Data.SqlClient" /> </connectionStrings>
在 Web.config 的 部分中,需要一个对 SQL Server Express aspnetdb.mdf 文件的连接,如您所见,SqlMembershipProvider 引用了该连接。
回到上文看一下 SqlMembershipProvider 的声明,下一个要利用的属性是 requiresQuestionAndAnswer 属性。该属性现在设置为 false,因此将移除新用户注册过程中的问题/答案部分。默认情况下,该属性设置为 true — 即,在用户注册应用程序的过程中收集问题/答案。收集这些信息后,最终用户一旦忘记密码,就可以利用各种控件提供的信息来获取自己的密码。因为媒体共享库没有获取密码的功能,所以问题/答案部分可以去掉。
然后将 requiresUniqueEmail 属性设置为 true,这表示每个用户必须在注册过程中输入一个成员身份数据库中没有保存过的电子邮件地址。如果最终用户提供的电子邮件地址已经存在,那么注册过程将出现一个验证错误。
后面的 passwordFormat、minRequiredNonalphanumericCharacters 和 minRequiredPasswordLength 属性用于控制密码在应用程序中的管理方式。本示例中的 passwordFormat 设置为 Hashed。这样设置将使 ASP.NET 先对所提供的密码进行哈希排列,然后再存储在数据库中。用户以后登录应用程序时,会对其所提供的密码进行哈希运算,将结果与数据库中存储的哈希字符串进行比较,以便判定数据库中是否存在匹配项。将 minRequiredNonalphanumericCharacters 设置为 0 之后,就允许提供不包含数字、字母等字符(例如 1、2、3、$、# 或 !)的密码。最后将 minRequiredPasswordLength 设置为 3,那么只要用户愿意,就可以输入只有三个字符的密码了。
但是,不要忘记,对 SqlMembershipProvider 作出的这些修改降低了应用程序的安全性。是简化用户登录到应用程序的过程,还是保证应用程序所需的安全性 — 您必须在这两者之间进行权衡,使用自己满意的做法。
应用到 SqlMembershipProvider 的设置,除了根目录文件 Web.config 中包含的那些设置之外,还有程序清单 9 中所示的其他一些设置,它们用于处理成员身份和角色管理系统。
程序清单 9. 根目录文件 Web.config 中的部分代码
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <roleManager enabled="true" /> <anonymousIdentification enabled="True" /> <authentication mode="Forms" /> </system.web> </configuration>
此处应用的设置首先启动角色管理系统(在默认情况下禁用该系统)。之后就可以在应用程序启动时从 Global.asax 文件设立管理员角色。应用程序紧接着将启动匿名身份验证功能,以便准许或拒绝匿名用户,最后再将应用程序的身份验证模式设置为基于窗体的身份验证模式。
完成这些设置后,就表示所有匿名用户都可以访问应用程序中的所有文件(除禁止所有用户访问的文件之外)。
那么如何禁止用户访问应用程序内的某些特定文件夹呢?下面我们来了解这个内容。
对其他 Web.config 文件应用设置
在根目录文件 Web.config 中配置好这些设置之后,下一步是在应用程序中放置额外的 Web.config 文件,定义拒绝访问应用程序“Library”和“Admin”文件夹的特定用户类型。
首先来看“Library”文件夹中包含的 Web.config 文件。该文件于程序清单 10 中所示。
程序清单 10. “Library”文件夹中的 Web.config 文件
<?xml version="1.0" encoding="utf-8"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <authorization> <deny users="?" /> </authorization> </system.web> </configuration>
如前所述,Web.config 文件可以嵌套。将 Web.config 文件放在“Library”文件夹中可以定义深入的规则,或覆盖“Library”文件夹中包含的所有文件夹或文件的规则。就本示例而言,我们只关心如何拒绝匿名访问“Library”文件夹中的每个页面。这是通过使用在 部分中嵌套的 元素实现的。在该元素内,通过使用 users 属性可设置一个拒绝所有匿名用户的规范。值为问号 ("?") 代表所有匿名用户。那么 意味着最终将拒绝所有匿名用户访问 Library 文件夹的内容。如果要查看该文件夹的内容,用户必须通过应用程序中提供的登录窗体验证自己的身份。
下一个要创建的 Web.config 将放在“Admin”文件夹中。该 Web.config 文件如程序清单 11 所示。
程序清单 11.“Admin”文件夹中的 Web.config 文件
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <authorization> <allow roles="Admin" /> <deny users="*" /> </authorization> </system.web> </configuration>
我们只希望属于管理员角色的注册用户拥有访问“Admin”文件夹内容的权限,所以该 Web.config 文件需要在文档的 部分同时使用 元素和 元素。
首先来看 元素,您可能注意到了,对“Library”文件夹中包含的 Web.config 文件应用的属性值与该元素中用户属性的值不相等。此处,我们需要用星号 ("*") 代替问号 ("?") 来表示要拒绝所有匿名用户。星号指代所有 用户,包括已注册和未注册的用户。
设置禁止所有用户浏览“Admin”文件夹后,接下来要做的是允许某些用户访问文件中包含的某一个文件。这通过使用 元素实现。我们将使用 roles 属性代替 users 属性来指定允许访问文件中页面的用户,因为在此处我们只关注属于“Admin”角色的用户。
为用户提供登录和注册窗体
到此为止,我们按照自己的意愿配置了应用程序的成员身份和角色管理,接下来为最终用户提供登录应用程序的方式。完成该任务的方法有多种,其中 Media Share Library Starter Kit 利用了 Login.aspx 页面上的登录服务器控件,如程序清单 12 所示。
程序清单 12. 使用登录服务器控件
<fieldset> <legend>Login</legend> <br /> You must first register before you can login. <br /> <br /> <asp:Login ID="Login1" runat="server" CreateUserUrl="~/Join.aspx" UserNameLabelText="Username:" > </asp:Login> </fieldset>
该 Login 服务器控件的代码并不复杂。仅有的两处功能扩展是使用 CreateUserUrl 和 UserNameLabelText 属性。CreateUserUrl 属性指向应用程序注册页面(这里是 Join.aspx)的位置,而 UserNameLabelText 属性仅用于更改 UserName 标签的名称。在浏览器中生成该页面后会产生以下结果,如图 6 所示。
图 6. 生成的登录服务器控件
Join.aspx 页面允许匿名用户注册该站点,从而使其成为注册用户。图 7 显示这一两阶段的注册过程。
图 7. 用户注册初学者工具包应用程序
注册过程的第一步由用户进行自定义。该过程的第二步是一个标准过程,尽管我们在 Web.config 文件中指定关闭成员身份系统的问题/答案功能,从而使 ASP.NET 自动移除了安全性问题/答案部分。该控件的代码如程序清单 13 所示。
程序清单 13. 使用 CreateUserWizard 服务器控件注册用户
<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" LoginCreatedUser="True"> <WizardSteps> <asp:WizardStep ID="WizardStep1" Runat="server" Title="Personal Information" StepType="Start"> <table width="100%"> <tr><td colspan="2">First Step: Enter your personal information</td></tr> <tr><td> Firstname: </td><td> <asp:TextBox ID="Firstname" Runat="server"></asp:TextBox> </td></tr><tr><td> Lastname: </td><td> <asp:TextBox ID="Lastname" Runat="server"></asp:TextBox> </td></tr><tr><td> Group: </td><td> <asp:TextBox ID="Group" Runat="server"></asp:TextBox> </td></tr> </table> </asp:WizardStep> <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server"> </asp:CreateUserWizardStep> <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server"> </asp:CompleteWizardStep> </WizardSteps> </asp:CreateUserWizard>
浏览过这段代码,您会发现 CreateUserWizard 控件中定义了三个向导步骤。第一步是通过使用 WizardStep 服务器控件定义的,它是该过程的一个自定义步骤。加入该步骤是为了收集用户的一些个人信息。收集到的这些信息片断之后会添加到内置的个性化系统中(稍后讨论该内容)。
第二个向导步骤 CreateUserWizardStep1 是默认的向导步骤,用于询问用户的登录名/密码以及电子邮件地址。该过程的最后一步是针对完成注册过程的用户的。
CreateUserWizard 控件中最值得关注的一个属性可能就是 LoginCreatedUser 属性。该属性设置为 True 时,CreateUserWizard 控件会自动将刚创建的用户登记到应用程序中。默认情况下,该属性设置为 False。
最终用户单击“Create User”按钮时,Join.aspx 页面将在代码隐藏页面中启动以下事件(如程序清单 14 所示)。
程序清单 14. 创建用户的按钮事件
Protected Sub CreateUserWizard1_ContinueButtonClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles CreateUserWizard1.ContinueButtonClick ' Assign Profile items entered through registration process. Profile.FirstName = Firstname.Text Profile.LastName = Lastname.Text Profile.Group = Group.Text Profile.MemberSince = DateTime.Now() Profile.Email = CreateUserWizard1.Email Response.Redirect("~/Default.aspx") End Sub
该事件会将各条用户的个人信息保存在个性化系统中,然后再将用户重定向为根目录中 Default.aspx 页面的注册用户。
使用个性化系统
正如您在上文的代码清单中看到的,我们存储了一些最终用户的个人信息。这些信息存储在 ASP.NET 2.0 提供的内置个性化系统中。
为了激活该系统,必须在根目录的 Web.config 文件中添加一些设置声明。如程序清单 15 所示。
程序清单 15. 声明应用程序的个性化属性
<profile> <properties> <add name="FirstName" /> <add name="LastName" /> <add name="Email" /> <add name="Group" /> <add name="MemberSince" type="System.DateTime" /> </properties> </profile>
个性化属性的声明在 Web.config 文件的 部分中进行。在 部分内创建一个 部分,在其中可以添加一系列 元素。这些 元素用于声明具体的配置文件属性。在本示例中要声明 5 个属性 — FirstName、LastName、Email、Group 和 MemberSince。MemberSince 属性甚至需要通过添加 type 属性来进一步定义,后者用于指定前者的属性类型(此处为 System.DateTime)。而其他配置文件属性则不需要进一步应用这一规范,这表示它们将应用默认的 System.String 类型。
将这小段代码放在 Web.config 中后,就可以按以下方式为这些属性赋值了:
Profile.FirstName = TextBox1.Text
您也可以使用自己赋值的属性值:
TextBox1.Text = Profile.Email
在下一篇 ASP.NET Jumpstart 文章中,您将了解到如何在一些 ASP.NET 页面的表述中使用这些配置文件属性。
应用样式
ASP.NET 2.0 还为您提供了在中央位置对页面应用样式的方法。ASP.NET 主题(本文前面提到过)允许将服务器控件以及其他页面元素的所有样式放置在应用程序中的同一个位置。
要构建集中样式的数据存储,可以在应用程序中创建一个名为 App_Themes 的文件夹。在该文件夹中再创建另一个文件夹,以便创建主题或样式集合,应用程序中的各个页面都可以使用该样式集合。将该文件夹命名为您的主题名。您可以在 App_Themes 文件夹中添加任意数量的主题。进行 Media Share Library Starter Kit 的基本安装时,只有一个标题为 Evjen 的主题。
主题可以包含一个皮肤或 CSS 文件集合。Evjen 主题同时包含这两个元素。CSS 文件是标准文件,处理它的方式应该与正常处理 CSS 文件的方式没有差别。而皮肤文件对于大多数人而言都不太熟悉。它是一个 XML 文件,用于声明应用程序中包含的服务器控件的标准外观显示。查看 Evjen.skin 文件时,您将看到服务器控件声明的一个简短列表。程序清单 16 显示其中一个控件的声明。
程序清单 16. Evjen.skin 文件中声明的菜单服务器控件
<asp:Menu runat="server" Font-Bold="True" StaticDisplayLevels="5" BackColor="#F7F6F3" DynamicHorizontalOffset="2" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#7C6F57" StaticSubMenuIndent="10px" Width="100%" BorderColor="Brown" BorderWidth="1"> <StaticSelectedStyle BackColor="#F7F6F3" /> <StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" /> <DynamicHoverStyle BackColor="#7C6F57" Font-Bold="False" ForeColor="White" /> <DynamicMenuStyle BackColor="#F7F6F3" /> <DynamicSelectedStyle BackColor="#F7F6F3" /> <DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" /> <StaticHoverStyle BackColor="#7C6F57" Font-Bold="True" ForeColor="White" /> </asp:Menu>
浏览该控件声明时,您会注意到代码中没有声明任何行为。而只是声明了样式。还要注意的一点是,该控件声明中没有使用 ID 属性。这是由于该服务器控件代码将应用到 Menu 服务器控件的每个示例,这里是指应用 Evjen 主题的页面上所使用的 Menu 服务器控件。
如何对一个页面应用 Evjen 主题(或您的自定义主题)?可以使用 @Page 指令中的 Theme 属性,程序清单 17 对此进行说明。
程序清单 17. 内容页面的 @Page 指令
<%@ Page Language="VB" MasterPageFile="~/MediaLibraryMain.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" Title="Media Share Library" Theme="Evjen" %>
如果想在一个中央位置保留所有样式设置,这是个不错的方法。一旦以后要修改应用程序的整体外观时,在同一个位置作出更改就可以在整个应用程序中反映出来。这真是太简单不过了