使用 IIS 进行 ASP.NET 2.0 成员/角色管理

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Calibri; panose-1:0 0 0 0 0 0 0 0 0 0; mso-font-alt:"Times New Roman"; mso-font-charset:0; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:auto; mso-font-signature:0 0 0 0 0 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","serif"; mso-fareast-font-family:宋体; mso-bidi-font-family:"Times New Roman"; mso-font-kerning:1.0pt;} span.msoIns {mso-style-type:export-only; mso-style-name:""; text-decoration:underline; text-underline:single; color:teal;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:10.0pt; mso-ansi-font-size:10.0pt; mso-bidi-font-size:10.0pt; mso-ascii-font-family:Calibri; mso-fareast-font-family:宋体; mso-hansi-font-family:Calibri; mso-font-kerning:0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

使用 IIS 进行 ASP.NET 2.0 成员/ 角色管理

<script type="text/JavaScript"> var alimama_pid="mm_10152573_225492_285551"; var alimama_titlecolor="0000FF"; var alimama_descolor ="000000"; var alimama_bgcolor="FFFFFF"; var alimama_bordercolor="E6E6E6"; var alimama_linkcolor="008000"; var alimama_sizecode="12"; var alimama_width=468; var alimama_height=60; var alimama_type=2; </script> <script src="http://p.alimama.com/inf.js" type="text/javascript"> </script>  

<script src="http://www.517sou.net/googleads.js"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script> <script> google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad); </script> <script type="text/javascript"> <!-- google_ad_client = "pub-2590217842048189"; /* 336x280 */ google_ad_slot = "7489839785"; google_ad_width = 336; google_ad_height = 280; //--> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script> <script> google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad); </script> 使用 IIS  进行 Microsoft ASP.NET 2.0  成员/ 角色管理

 1  部分:安全和配置概述
发布日期: 2006-2-10 |  更新日期: 2006-2-10
Peter Kellner
http://peterkellner.net/

适用于:
   Microsoft ASP.NET 2.0
   Microsoft Visual Studio 2005
   Microsoft Internet 
信息服务

摘要:Peter Kellner  就创建应用程序来管理 Microsoft ASP.NET 2.0  成员身份数据库写了两篇文章,这是第一篇。本文主要论述如何保证解决方案的安全性以确保只有适合的管理员才能访问这些数据。

摘要
本 系列由两篇文章组成,论述如何安全使用和设置用于管理 ASP.NET Membership  Roles  的三层解决方案,本文是第一篇。本文将主 要论述如何配置、使用以及(最重要的是)保证此解决方案的安全性,并概述如何将其在典型的 Microsoft ASP.NET 2.0 Web  解决方 案中实现。Membership  Roles  对象被视为可运作,而不用深究其内部结构。管理 Members  Roles  似乎与管理简单数据 源中的数据无异。在第二篇文章中,将详细说明这些控件和对象的内部结构,以便开发人员能够使用类似的技术创建自己的控件和对象。

简介
ASP.NET 2.0 
将 用户身份验证直接扩展到了应用程序编程领域。使用标准的 .NET  库引用 (system.web.security) ,开发人员只需另外进行非常少的 工作就可以为其应用程序创建完全身份验证。请记住,必须执行必要的操作以尽可能保证创建的应用程序在使用期间的安全性。

本文概述了安全机制并显示了示例安全设置,这些设置是为 Web  应用程序创建安全环境的基本要素。ASP.NET 2.0  提供了许多不同的配置选项,这些选项是否必要取决于安全要求。本文将介绍这些配置选项的优缺点。

安全性注意事项
保证物理环境的安全性

人们常说,计算机的安全性由计算机前端面板上的电源开关来决定。无论操作系统级别对系统的保护有多么严密,物理保护都是最基本的。所以必须假定任何有权以物理方式访问计算机的用户始终能够以某种方式危害计算机的完整性。

有关推荐的保证计算机物理环境安全性最佳做法的详细信息,请参阅 Microsoft TechNet  上的这篇文章(英文)。

保证域环境的安全性

必须遵循设置用户帐户、密码和权限的最佳做法。例如,如果不具有相应权限的用户能够直接访问包含 Web  应用程序所用的安全数据的数据库,则该应用程序可能会受到危害。

有关保证计算机域环境安全性的详细信息,请参阅 Microsoft Security Home Page  上的以下几篇文章(英文),其中给出了许多非常有帮助的建议和提示。

保证 .NET  环境的安全性

.NET 
环 境允许设置代码访问安全性。这意味着各个系统和应用程序库可以与不同的信任级别相关联。这在某些环境中是非常重要的,例如,可以运行多个 Web  应用程 序的共享宿主环境。可能由不同用户拥有的每个 Web  应用程序可能会要求彼此隔离与保护。此外,如果不进行这种隔离,每个 Web  应用程序都可能影响 关键的系统功能。

本文假定 ASP.NET  用户(IIS  代表该用户运行)以最高信任级别运行。这就好像 Web  应用程序在专门环境 中运行一样。有关如何使用代码级别安全性来增强 Web  服务器安全性的详细信息,请参阅 MSDN  文 章 Using Code Access Security with ASP.NET (英文)。

ASP.NET 
 IIS  的关系

在 与 IIS  配合工作时,ASP.NET  支持三种身份验证提供程序:Forms  身份验证(使用应用程序特定的逻辑)、Passport  身份验证 (由 Microsoft  提供的集中身份验证服务)和 Windows  身份验证(使用直接通过 IIS  提供的身份验证)。本文使用的 是 ASP.NET  项目的默认身份验证:Forms  身份验证。身份验证模式在 web.config  文件中指定。语法选择如下。

<authentication mode = "{Windows|Forms|Passport|None}">
</authentication>


这篇文章(英文)的流程图中描述了用户从 Web  客户端登录时要遵循的流程。

请记住,这篇文章编写于 2001  年,当时的流程是相应于 IIS 5.1  而言的,而不是目前的 IIS 6.0  或更高版本。
按此在新窗口打开图片
 1IIS  ASP.NET  之间的安全流程

ASP.NET 2.0 
网站中基于角色的安全性
初始安装与配置

web.config 
文件/ 不常改动项

web.config 
文 件中设置了一些影响 ASP.NET 2.0 Web  应用程序总体运行情况的参数。示例参数包括,对成员身份提供程序(或数据库)的引用、所需密码强度 以及是否要求注册电子邮件。下面显示了 web.config  文件中的相关部分,其中包含最低安全性配置值示例。详细信息可通过以下方式获得:访 问 Visual Studio 2005  帮助,然后查阅“Membership Members” 。每个安全性参数在此均有详细说明。

<providers>
<remove name="AspNetSqlMembershipProvider"/>
<add name="AspNetSqlMembershipProvider" 
type="System.Web.Security.SqlMembershipProvider, 
System.Web, Version=2.0.0.0, Culture=neutral, 
PublicKeyToken=b03f5f7f11d50a3a" 
connectionStringName="LocalSqlServer"  
enablePasswordRetrieval="false" 
enablePasswordReset="true" 
requiresQuestionAndAnswer="true" 
applicationName="/" 
requiresUniqueEmail="false" 
minRequiredPasswordLength="1" 
minRequiredNonalphanumericCharacters="0" 
passwordFormat="Hashed" 
maxInvalidPasswordAttempts="5" 
passwordAttemptWindow="10" 
passwordStrengthRegularExpression=""
commentTimeout=""/>
</providers>



除 了上面显示的 web.config  文件部分外,machine.config  文件中包含与 Membership  关联的数据库的默认连接字符串。 可以在 web.config  文件中配置一个不同的连接字符串。要添加附加安全性,可以编码连接字符串,并可以加密 Membership  数据库密 码。许多文章已针对这些折衷方法进行了论述。Microsoft  的快速入门指南(英文)中提供了有关如何在 web.config  文件中使用加密的很 好的示例。

web.config 
文件/.aspx  页面安全性

可以为 Web  应 用程序中的每个网页指定一个安全级别。通过指定访问页面所需具备的角色即可执行此操作。web.config  文件中的语法非常简单。例如,以 下 web.config  片段指定了只有角色被指定为 Administrator  的用户才能访问网页 MembershipGrid.aspx

<system.web>
<location path="MembershipGrid.aspx" >
<system.web>
<authorization >
<allow roles="Administrators"/>
</authorization>
</system.web>
</location>
</system.web>



又例如,要指定只有特定角色才能访问某个子目录中的所有页面,则 web.config  文件如下。在本示例中,只有角色被指定为 Administrator  的用户才能访问 ~/AdminDir  路径中的所有文件。

<system.web>
<location path="AdminDir" >
<system.web>
<authorization >
<allow roles="Administrators"/>
</authorization>
</system.web>
</location>
</system.web>



web.config 
文件/ 内部 .aspx  页面安全性

很 多时候,需要提供比上述更精确的安全性。也就是说,可能需要对控件(例如按钮)或 aspx  页面提供保护。为此,需要以编程方式更改与会受影响的控件关 联的属性。例如,如果需要根据用户角色隐藏某个删除按钮,则需要执行两步操作:首先,应该把名为 ShowButtonBasedOnRole  的方法添 加到网页的 codebehind  类。如果用户具备要求的角色,将返回 true ;如果用户不具备要求的角色,将返回 false

protected bool ShowButtonBasedOnRole(string RoleOfInterest)
{
return User.IsInRole(RoleOfInterest);   
}



然后,在实际 aspx  页面上,基于内含代码方法 ShowButtonBasedOnRole  来设置该按钮的可见性属性。该按钮的实际声明大致如下。

<asp:Button
ID="Button1" runat="server" Text="
按钮"
Visible='<%# (bool) ShowDeleteRowBasedOnRole("administrator") %>'> />



如果按钮基于所设置的多个角色中的任何一个,则传入参数可更改为字符串,并且在返回用户是否被指定为其中某个角色的答案之前,将检查所有这些角色。

使用成员/ 角色管理器 aspx  页面

要 使用本项中包含的 aspx  页面 (Membership.aspx) ,需要执行以下几步操作。首先,需要复制文章项目文件中的两个数据类并将它们包含 在目标项目的 app_code  目录中。这两个文件为 MembershipDataObject.cs  RoleDataObject.cs 。然 后,需要将 aspx  文件 Membership.aspx  及其内含代码页面 Membership.aspx.cs  移到当前项目中。

一 定要对此页面提供保护,以防止任何未被指定为 Administrator  角色的用户访问它。否则,任何用户都能够修改其他用户的登录信息。为此,请确 保 Membership.aspx  页面在 web.config  文件中受到保护。web.config  文件中用来实现此目的的示例行如下。

<system.web>
<location path="Membership.aspx" >
<system.web>
<authorization >
<allow roles="Administrators"/>
</authorization>
</system.web>
</location>
</system.web>



由于此页面受到了保护,因此当前登录的用户帐户必须被指定为 Administrator  角色才能访问此页面。

实 现此目的的最好方法是执行一次下面的代码,然后从 Web  服务器中删除该代码。例如,可以在 ASP.NET  网页的页面加载事件中执行。然后在调用此 页面之后,从服务器中将其删除。这样,只有使用密码登录帐户 admin  才能访问 Membership Management  页面。

Roles.CreateRole("Administrator");
Roles.CreateRole("User");
Roles.CreateRole("Guest");
Membership.CreateUser("admin", "
在此输入强密码");
Roles.AddUserToRole("admin", "Administrator");



结论
设 置任何网站时,都务必确认将使用该网站的用户并了解他们的相关安全性要求。例如,如果网站将供公司的内部组使用,不会有外部用户访问,且不包含敏感数据, 那么配置简单安全性就足够了。即,不需要加密、松散密码约束等。身份验证可以作为跟踪输入数据的用户身份的一种便利方法。反之,如果网站 在 Internet  上并且会处理机密数据,则一定要尽可能锁定该网站,仅允许通过身份验证的用户进行访问。

本文简要介绍了在设 置 ASP.NET  网站的安全性时需要注意的事项,说明了如何添加安全页面来修改登录到网站的用户的 Membership  Role  信息。本系 列由两篇文章组成,下一篇文章将假定读者已了解开发网站时设置安全性方面的问题,并将详细介绍 Membership Management  页面的工作 方式。

 2  部分:实现

摘要:本文介绍如何通过创建三层结构式 ASP.NET 2.0  应用程序来维护 IIS  生产服务器中的成员身份数据库和角色数据库。

简介
成员身份编辑器

Microsoft Visual Studio 2005 
版 本中没有用于维护 Microsoft IIS  中的成员身份数据库和角色数据库的 现成 解决方案。将开发环境中的应用程序移至 IIS  生产服务器时 这就会是个问题。Microsoft  提供的实用程序 ASP.NET Web Configuration  只能在非生产的开发环境中运行。本文及其关 联代码将通过对成员和角色管理实现三层式解决方案,同时使用 Microsoft ASP.NET  标准工具,来解决这个问题。这意味着该实用程序将可在 任何 ASP.NET 2.0  环境(包括 IIS )中运行。该解决方案十分灵活,可以轻易添加到任何现有的 ASP.NET 2.0  网站项目中。

该 解决方案的层定义如下。第一层 ASP.NET  页面(也称为表示层)通过对象数据源与两个业务对象进行连接。这些业务对象起中间层作用,是成员和角色的 包装程序。第三层(即后端)由 ASP.NET  提供的成员身份和角色管理器 API  组成。中间层对象可以轻松地加入任何 ASP.NET 2.0  项 目,并且几乎无需进行任何更改就可以直接使用。

本文深入地介绍了中间层(即数据对象及其关联 ObjectDataSource )的实 现。接着,介绍了如何在使用 Microsoft SQL Server Express 2005 (捆绑有 Visual Studio 2005 ) 的 ASP.NET Web  项目中使用这些对象。但是由于 Microsoft  提供的成员身份 API  使用其提供商的技术,因此此处介绍的解决方案 与数据库无关。从 LDAPSQL Server  Oracle  即可轻松获得成员身份和角色信息。

采用的技术
ObjectDataSource

定 义了两个 ObjectDataSource  实例。一个是有关成员身份数据(用户名、创建日期、批准状态等)的,另一个是有关角色(管理员、朋友等) 的。这两个数据源均完全填充了所有数据访问方法,即两者都包含执行插入、更新、删除和选择的 Member  函数。两 个 ObjectDataSource  实例都返回 Generic List  类型,这意味着在 GridView  中,列名将自动设置 为 ObjectDataSource  的属性值名。此外,还实现了自定义排序,以便用户可以单击 GridView  中的列标题来根据需要对数据进行正 向或反向排序。

SQL Server Express 2005 
 Web.Config

成员身份数据库和角色数据库 的数据提供程序源是 SQL Server Express 2005 。为实现这一点,需要在 web.config  文件中设置相应的条目。本文稍后将 对如何从头开始设置新项目进行简要的介绍。web.config  文件中未提及 SQL Server Express 2005  的连接字符串,因为它 已在 Microsoft .NET 2.0 Framework  的默认部分 Machine.Config  文件中定义。

支持 IIS5.1  6.0

Web 
服 务器可以为 5.1  版,也可以为 6.0  版。若要对登录 Web  应用程序的多个用户进行测试,必须使用 IIS 。内置开发 Web  服务器不能正确 保持各不同登录用户的状态。内置开发 Web  服务器不能正确保持各不同登录用户的状态。尽管可以使 Asp.net Web  配置工具与 IIS  一起 工作,但尚未完成实现这一目的所必需的附加安全工作。

GridView 
控件

GridView 
用 于显示成员身份和角色的数据。如上文所述,由于使用了 ObjectDataSource  Generic  类型,GridView  的列名将自动 以 ObjectDataSource  的属性值命名。如果没有使用 Generic  类型,则列名恢复为无意义的默认值,必须手动逐个进行编辑。

应用程序和项目
运 行此实用程序所需的项目非常简单,并且是独立的。项目文件可以下载,包含功能完整的示例。由于用户和角色没有直接访问数据库的权限,因此所要做的事情就是 获取三个数据对象(MembershipDataObject.cs MembershipUserSortable.cs  RoleDataObject.cs ,请参见图 2 )。
按此在新窗口打开图片
 2 :成员身份编辑器项目

SamplePages 
文件夹中有几个其他的示例,演示了前面提及的模块的用法。图 1  中显示的 Membership.aspx  即是其中一例,它可用于选择、更新、插入及删除成员和角色,以及为成员分配角色。

使用已有工作成员身份模块的工作 ASP.NET 2.0  应用程序时,无需对这些页面进行已做配置之外的外部配置。可以将这些文件直接复制到项目中,复制后即可使用。

如果是第一次在应用程序中实现成员身份和角色管理,则创建使用这些对象的解决方案的过程如下,

1. 
使用 Visual Studio 2005  创建类型为 ASP.NET  网站的新 Web  项目。  
2. 
单击菜单上的 Website / ASP.NET Configuration (网站/ASP.NET  配置)。 
3. 
按 照向导提示的步骤( 7 )进行操作来创建一些示例用户和角色。这将在当前项目中有效地创建有效 web.config  文件,其中包含能够启动并运 行成员管理的充足信息。默认情况下,它将在其默认配置中使用 SQL Server Express 2005 
4. 
在项目中添加三个 .cs  文件,然后添加示例 .aspx  页面作为示例。
 
ObjectDataSource 
详细信息
采 用 ObjectDataSource  技术可以创建作用与 SqlDataSource  非常相似的数据源,即它提供允许从永久数据存储区(例如数据 库)中进行选择、更新、插入和删除记录(或类似记录的对象)的界面。本文以下各部分将讨论 ObjectDataSource  用于操作成员身份的对象 (即类文件)。其在项目中的名称为 MembershipUserODS.cs

 (MembershipUserODS)

由 于是通过 Microsoft  成员身份 API  检索数据,因此使用 ObjectDataSource  来解决问题。第一步是创建独立的类,该类 对 MembershipUser  进行包装,以便它可以与 ObjectDataSource  关联。下例中介绍了一组需要实现的典型方法,本文以下各 部分将介绍如何实现每个成员函数。本文省略了许多细节,但本文附带的源代码中包含这些细节。

[DataObject(true)
public class MembershipUserWrapper {

  [DataObjectMethod(DataObjectMethodType.Select, true)]
  static public Collection<MembershipUserWrapper> GetMembers(string
       sortData) {
    return GetMembers(true, true, null, sortData); 
  }

  [DataObjectMethod(DataObjectMethodType.Insert, true)]
  static public void Insert(string UserName, bool isApproved,
string comment, DateTime lastLockoutDate, ...) {
  }
        
  [DataObjectMethod(DataObjectMethodType.Delete, true)]
  static public void Delete(object UserName, string Original_UserName){
    Membership.DeleteUser(Original_UserName, true);
  }
  
  [DataObjectMethod(DataObjectMethodType.Update, true)]
  static public void Update(string original_UserName,string email,...){ 
  }
}



类声明

上 面显示的类声明因具有属性 [(DataObject(true)] ,比较特殊。此属性告 诉 Visual Studio 2005 ObjectDataSource  创建向导,在数据类中搜索 DataObject  时只查找具有此特殊属 性的成员。请参阅本部分中介绍在何处为 GridView  组件分配此类的示例。

Insert 
方法

各部分的细节都涉及以非常简单的方式使用 Microsoft  提供的成员身份 API 。例如,下面是一个较详细的典型 Insert  方法。

[DataObjectMethod(DataObjectMethodType.Insert,true)]
static public void Insert(string userName, string password,)
{
   MembershipCreateStatus status;
      Membership.CreateUser(userName, password,);
}



此 类 Insert  是多态的,这意味着可以存在用于不同目的的多个 Insert  方法。例如,动态决定是否应该根据环境批准创建的用户时,可能需要使用 它。又如,在管理屏幕中创建的新用户可能想创建默认为已批准的用户,而用户注册屏幕可能默认为未批准。为此,需要另一个具有额外参数的 Insert  方 法。可实现此目标的 Insert  方法大致如下。

[DataObjectMethod(DataObjectMethodType.Insert,false)]
static public void Insert(string userName, string password, bool isApproved)
{
MembershipCreateStatus status;
   Membership.CreateUser(UserName, password,,
      isApproved, out status);
}



与此处所列的其他方法一样,显示的示例并非附带源中实际存在的示例。此处的示例是为了说明各个方法的典型用法。源代码中包含的用法更为完备且带有注释。

Update 
方法

Update 
方 法是实现成员身份 API  的一种非常简单的方法。与 Insert  方法一样,Update  方法也可以有多种实现。此处只介绍一种实现。在可下载的代 码中,有更多 Update  的多态实现,其中一种只设置 IsApproved  属性(如下例所示)。

[DataObjectMethod(DataObjectMethodType.Update,false)]
static public void Update(string UserName,bool isApproved)
{
   bool dirtyFlag = false;
   MembershipUser mu = Membership.GetUser(UserName);
   if (mu.isApproved != isApproved)
   {
      dirtyFlag = true;
      mu.IsApproved = isApproved;
   }
   if (dirtyFlag == true)
   {
      Membership.UpdateUser(mu);
   }
}



Delete 
方法

Delete 
方法是最简单的方法,它只使用一个参数 UserName

static public void Delete(string UserName)
{
   Membership.DeleteUser(UserName,true);
}



具有 Sort  属性的 Select  方法

在本示例中,Select  方法 GetMembers  具有多个组件,每个组件都值得介绍。首先介绍其返回的值,然后是方法本身,最后介绍其如何排序返回值。

Select 
方法的返回值(类型为 Collection
Select 
方 法(也称为 Get )的返回值为 Generic Collection  类。使用 Generic  是因为最终与该类关联 的 ObjectDataSource  使用反射来确定列名和类型。这些名称和类型与返回的每行数据相关联。此方法与 SqlDataSource  使用 表或存储过程的数据库元数据来确定每行的列名相同。由于 Select  方法的返回类型为 MembershipUserWrapper (继承 自 MembershipUser ),此类的大多数属性都是与 MembershipUser  关联的相同属性。这些属性包括,

• ProviderUserKey 
• UserName 
• LastLockoutDate  
• CreationDate  
• PasswordQuestion  
• LastActivityDate  
• ProviderName  
• IsLockedOut  
• Email  
• LastLoginDate 
• IsOnline
• LastPasswordChangedDate 
• Comment 
 
在 此插一句,属性值有一个非常好的特点 -  它们可以是只读的(无设置方法)、只写的(无读取方法),当然也可以是读/ 写的。 ObjectDataSource  向导考虑到了这一点,并创建了相应的参数,这样在使用 ObjectDataSource  呈现数据控件时,只有可更 新(读/ 写)的字段能够编辑。这意味着您不能更改某些属性,例如 UserName  属性。如果这一点现在还不清楚,稍后在我们更详细地阐 述 ObjectDataSource  和数据组件时,就容易明白。

Select 
方法本身
 Insert  Update  方 法一样,Select  方法也是多态的。有多少种情况,就可以有多少种 Select  方法。例如,最好能够使用 Select  方法按照用户的批准状态 (已批准、未批准或两者)来选择用户。通常,有一个 Get  方法具有与其关联的尽可能多的参数,其他 Get  方法对其进行调用。在我们的示例中,有三 个 Get  方法,一个检索所有记录,一个根据批准状态检索记录,一个根据选择字符串检索单个记录。下例介绍的是调用返回所有用户的方法。将两个布尔值均 设置为 true ,可以返回所有用户。

[DataObjectMethod(DataObjectMethodType.Select, true)]
static public List<MembershipData> GetMembers(string sortData)
{
   return GetMembers(true,true,null,null);
}



下 面的示例介绍了一个较详细的 Get  方法。此示例仅介绍方法的开头部分,未介绍方法的详细信息,包括完成属性分配、按批准状态筛选并拒绝不满足条件的记 录,以及应用排序条件。此示例后面是有关排序条件的详细说明。(请注意,对包含数百个用户 [ 不超过五百 的数据库调用 GetAllUsers ,很快 就会成为代价非常高昂的操作。)

[DataObjectMethod(DataObjectMethodType.Select, true)]
static public List<MembershipData> GetMembers(bool AllApprUsers, 
    bool AllNotApprUsers, string UserToFind, string sortData)
{
   List<MembershipData> memberList = new List<MembershipData>();
   MembershipUserCollection muc = Membership.GetAllUsers();
   foreach (MembershipUser mu in muc)
   {
      MembershipData md = new MembershipData();
      md.Comment = mu.Comment;
      md.CreationDate = mu.CreationDate;
            ...


自定义排序条件
请 注意,在前面的代码中,名为 sortData  的参数字符串传递到了 GetMembers  中。如果在 ObjectDataSource  声明 中,SortParameterName  被指定为其一个属性,则此参数将自动传递到所有 Select  方法。其值将为数据控件列中 的 SortExpression  属性指定的名称。在我们的示例中,数据控件为 GridView

Comparer 
方法是根据传递 给 GetMembers  方法的 sortName  参数调用的。由于这些 ASP.NET  网页无状态,因此必须假定当前排序的方向(正向或反向)存 储在视图状态中。每次调用都颠倒前一次调用的方向。即用户单击列标题时,在正向排序和反向排序之间切换。

假定使用的 是 GridView ,传递到 GetMembers(sortData)  的参数中包含 GridView  列的属 性 SortExpression  中的数据。如果请求反向排序,则“DESC” 一词附加在排序字符串后面。例如,用户第一次单击 Email  列时,传 递到 GetMembers  sortData “Email” 。用户第二次单击该列时,参数 sortData  就变为 “Email DESC” ,然后是“Email”“Email DESC” ,依此类推。特别需要注意的是,第一次加载页面时,传递 的 sortData  参数是零长度的字符串(非空)。下面是 GetMembers  方法的一部分,该方法检索数据并对其进行排序,以便按正确的顺序返 回这些数据。

[DataObjectMethod(DataObjectMethodType.Select, true)]
static public List<MembershipData> GetMembers(string sortData)
{
  List<MembershipData> memberList = new List<MembershipData>();
  MembershipUserCollection muc = Membership.GetAllUsers();
  List<MembershipUser> memberList = new List<MembershipUser>(muc);

  foreach (MembershipUser mu in muc)
  {
    MembershipData md = new MembershipData(mu);
    memberList.Add(md);
  }

  ... Code that implements Comparison

   memberList.Sort(comparison);
  
  return memberList;
}



在下一部分中,将此并入 GridView  中后,就比较清楚了。

ObjectDataSource 
声明

声 明 ObjectDataSource  最简单的方法是,先使用 Visual Studio 2005  向导创建一个空的 ASP.NET  页面,然后 将数据控件中的数据控件拖放到工具栏中。创建 ObjectDataSource  后,可以获取新建 ObjectDataSource  右上角的小标 记;然后单击 Configure Data Source (配置数据源)打开一个向导,其中显示“Configure Data Source- ObjectDataSource1” (配置数据源 - ObjectDataSource1 )(请参见图 3 )。
按此在新窗口打开图片
 3 :配置 ObjectDataSource

此 时,将显示可与 ObjectDataSource  关联的两个类。MembershipUserODS  是本文的主要主题。 RoleDataObject  基本相同,但其封装成员身份角色。另外,请记住,此处显示的只是声明具有特殊类属 性 [DataObject(true)] (在 类定义 中介绍)的对象。

选择 MembershipUserODS  后,将显示一个具 有四个选项卡的对话框。要通过 MembershipUserODS  类调用的方法将在这些选项卡中定义。SelectUpdate Insert  Delete  方法将与 MembershipUserODS  中的成员函数关联。在许多情况下,类中都有多种方法适用于其中每种情 况。必须根据所需数据方案选择一个适当的方法。图 4  中显示了这四个选项卡。默认情况下,将在这些选项卡中填充标有特殊属 性 [DataObjectMethod(DataObjectMethodType.Select, false)]  的成员。当然,此特殊属性 是 Select  的默认值。将表达式 DataObjectMethodType.Select  改 为 DataObjectMethodType.Insert DataObjectMethodType.Update  DataObjectMethodType.Delete  将为其他选项卡确定相应的默认 值。第二个参数是一个布尔值,表示此方法(请记住,它能以多态方式定义)是默认方法,应在选项卡控件中使用。

Select 
方法

如 前面在介绍 MembershipUserODS  类的部分中所述,GetMembers  函数返回 Generic Collection  类。这样, 此处定义的 ObjectDataSourceMembershipUser  控件可以使用反射,并确定与 GetMembers  调用关联的调用参数。 在本示例中,用于调用 GetMembers  的参数是 returnAllApprovedUsers returnAllNotApprovedUsersuserNameToFind  sortData 。基于此, 新 ObjectDataSource  的实际定义如下。
按此在新窗口打开图片
 4 :指定 Select  方法

<asp:ObjectDataSource ID="ObjectDataSourceMembershipUser"runat="server" 
    SelectMethod="GetMembers" UpdateMethod="Update" 
    SortParameterName="SortData"
    TypeName="MembershipUtilities.MembershipDataODS" 
    DeleteMethod="Delete" InsertMethod="Insert" >
    <SelectParameters>
      <asp:Parameter Name="returnAllApprovedUsers" Type="Boolean" />
      <asp:Parameter Name="returnAllApprovedUsers" Type="Boolean"/>
      <asp:Parameter Name="usernameToFind"         Type=" String" />
      <asp:Parameter Name="sortData"               Type=" String" />
    </SelectParameters>
    ...
    ...
</asp:ObjectDataSource>



Insert 
方法

在 本示例中,Insert  方法被指定给成员函数 Insert() 。请注意,调用此方法时只使用了两个参数,UserName  Password (请 参见图 5 )。参数的数目必须等于 ObjectDataSource  中声明的参数的数目。ObjectDataSource  中的参数声明如下所示。 另一个定义的函数为 Insert Member ,用于添加第三个参数,approvalStatus 。如果此 ObjectDataSource  的功 能要包括在设置 approvalStatus  时进行插入操作,则应从下拉列表中选择其他 Insert  方法。这会导致以 下 InsertParameters  插入 .aspx  页面中。如果选择包含两个参数的方法,则块中不会包括名 为 isApproved  asp:Parameter 。请记住,本示例可能与附带的源代码不一致,此处仅作为示例。附带的源代码要完整得多。
按此在新窗口打开图片
 5 :指定 Insert  方法

<asp:ObjectDataSource ID="ObjectDataSourceMembershipUser"runat="server" 
    SelectMethod="GetMembers"UpdateMethod="GetMembers" 
    SortParameterName="SortData"
    TypeName="MembershipUtilities.MembershipDataObject" 
    DeleteMethod="Delete" InsertMethod="Insert">
    <InsertParameters>
        <asp:Parameter Name="userName" Type="String" />
        <asp:Parameter Name="password" Type="String" />
        <asp:Parameter Name="isApproved" Type="Boolean" />
    </InsertParameters>
    ...
</asp:ObjectDataSource>



请记住,如果使用的是具有最少参数的 Insert  方法,则需要在方法中设置默认密码。在生产系统中,这是个糟糕的办法。有关如何处理插入的更好示例,请参阅附带的源代码。具体地说,请参阅 Membership.aspx  页面了解此功能。

Update 
方法

在 本示例中,Update  方法被指定给成员函数 Update() 。请注意,调用此方法时使用了多个参数,UserNameEmail isApproved  Comment (请参见图 6 )。此外,还有一种 Update  方法,它包含所有可更新参数。如果要创建具有尽可能多的更新 功能的控件,这很有用。与 Insert  一样,为此 ObjectDataSource  选择适当的 Update  方法。完成向导后,将自动创 建 UpdateParameters ,如下所示。
按此在新窗口打开图片
 6 :指定 Update  方法

<asp:ObjectDataSource ID="ObjectDataSourceMembershipUser"runat="server" 
    SelectMethod="GetMembers" InsertMethod="Insert"
    SortParameterName="SortData"
    TypeName="MembershipUtilities.MembershipUserODS" 
    UpdateMethod="Update" DeleteMethod="Delete">
    <UpdateParameters>
        <asp:Parameter Name="Original_UserName" />
        <asp:Parameter Name="email" Type="String" />
        <asp:Parameter Name="isApproved" Type="Boolean" />
        <asp:Parameter Name="comment" Type="String" />
    </UpdateParameters>
    ...
    ...
</asp:ObjectDataSource>



Delete 
方法

在本示例中,Delete  方法被指定给成员函数 Delete() 。当然,只需一个 Delete  方法(请参见图 7 )。下面是支持此 Delete  方法的 ObjectDataSource  的声明。
按此在新窗口打开图片
 7 :指定 Delete  方法

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
    SelectMethod="GetMembers" InsertMethod="Insert"
    SortParameterName="SortData"
    TypeName="MembershipUtilities.MembershipUserODS" 
    UpdateMethod="Update" DeleteMethod="Delete">
    <DeleteParameters>
        <asp:Parameter Name="UserName" />
        <asp:Parameter Name="Original_UserName" />
    </DeleteParameters>
    ...
</asp:ObjectDataSource>



 (RoleDataObject)

与 成员身份一样,设置角色时也使用其自己的 DataObject 。由于角色无特殊之处,本文不对其设置进行详细介绍。了解成员身 份 DataObject  的设置方式后,即可了解角色的设置方式。在成员身份中,封装成员身份 API  Microsoft C#  对象 是 MembershipDataObject.cs 。封装角色 API  的相似类是 RoleDataObject.cs

GridView 
中的 ObjectDataSource (数据控件)
本 文的前面部分中已建立了成员身份用户和角色的类声明。此外,还在 ASP.NET  页面中加入了完整的 ObjectDataSource  对象。最后一 步是创建用户界面,也称为应用程序的用户互动层或表示层。由于创建的对象完成了这么多的工作,因此所需做的只是创建简单的 GridView  并将其 与 ObjectDataSource  关联。步骤如下,
1. 
 ASP.NET  页面设计器的可视模式下,将 GridView  数据组件拖放到先前创建的 ObjectDataSource  关联页面中。  
2. 
启用选择、删除、更新、插入和排序。 
 8  显示的是与配置 Gridview  关联的对话框。
按此在新窗口打开图片
 8 :配置 GridView

此 处应特别注意,下面显示的 GridView  控件中的 DataKeyNames  是自动设置的。这是因为,在具有属 性 [DataObjectField(true)]  MembershipUserSortable  类中对主键添加了标记,如下所示。请注意,由 于 UserName  MembershipUser  类的属性,需要在扩展 MembershipUser  的类中提供默认属性。由于是只读属性, 因此只声明了 Get  方法(对于 MembershipUserUserName  是公共虚拟的)。

[DataObjectField(true)]
public override string UserName {
  get { return base.UserName;
}



GridView 
中有一个属性必须手动设置,必须在控件中设置主键。为此,需要将属性 DataKeyName  UserName  相关联。GridView  声明如下。

<asp:GridView ID="GridView1" DataKeyNames="UserName" runat="server" 
        AllowPaging="True" AutoGenerateColumns="False"
        DataSourceID="ObjectDataSourceMembershipUser"
        AllowSorting="True">
    <Columns>
    ...
    ...



结论
至 此,您现在应熟悉如何创建自己的三层结构式 ASP.NET  应用程序。此外,目前还要有两个可任意使用来封装成员和角色的对象。例如,现在可以使 用 DetailView  控件,在几分钟内创建一个针对成员的完整 DetailView  界面,用于对成员进行导航、插入、更新及删除操作。试一试 吧!

我并未具体介绍如何实现添加、更新和删除成员或角色。如果您查看源代码,就会发现我使用 API  的方法非常简单。在此详细介绍那些调用并无多大用处,因为我确信,如果您仍在阅读本文,您会和我一样,边学边实践。

今 年我有幸参加了在奥兰多举办的 MS TechEd  和在洛杉矶举办的 PDC ,有机会向 ASP.NET  小组请教了许多问题。特别感 谢 Brad Millington  Stefan Schackow  在这几周解答了我提出的许多问题,感 谢 Jeff King  Brian Goldfarb  对本文进行润色提供的所有帮助。从某些方面来讲,本文是对提供过帮助的人的回报,希望他们将 来不必回答这么多问题。

作者简介

Peter Kellner 
 1990  年创办 了 73rd Street Associates ,在此成功地为全国 500  多家客户提供了有关大学医务室调度、保险公司管理和一站式医生诊所管理的 系统。十年后(即 2000  年),一家大型保险公司收购了 73rd Street Associates ,于是 Peter  开始了作为独立软件顾问 的新职业生涯。目前,他涉及的技术中包括 ASP.NETOracleJavaVOiP ,很快会包括 SQL Server 。不工作 时,Peter  将他的大部分空闲时间花在骑车旅行上。他已骑车周游了全世界。最近,他和妻子 Tammy  只用了 27  天就完成了从美国加利福尼亚州 骑车到乔治亚州的旅程。

他的博客站点为 http://peterkellner.net/ 。您可以在下载区域找到本文和所列的代码。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值