15.4 建立自己的提供程序
现在讲述建立自己的提供程序,以在ASP.NET 2.0应用程序中使用的过程。实际上,提供程序并不难建立,甚至可以直接在ASP.NET 2.0项目中创建。下面的示例将演示如何建立一个可以在XML文件中使用的成员提供程序。一些较小的Web站点常常需要创建这样的提供程序。而较大的Web站点和基于Web的应用程序一般要使用某种类型的数据库,而不是使用XML文件来管理用户。
在建立自己的成员提供程序时,有两种方法:从SqlMembershipProvider类或MembershipProvider类中派生,以实现需要的功能。只有希望扩展或改变与SQL交互的成员系统的行为时,才应从SqlMembershipProvider类中派生。这里的目的是建立一个只读的XML成员提供程序,所以不应从这个类中派生。而最好以MembershipProvider类的内容为基础。
15.4.1 创建CustomProviders应用程序
这个示例要以用户选择的语言创建一个新的Web站点项目CustomProviders。对于这个示例来说,需要直接在Web应用程序中建立新的成员提供程序。另一种方法是在类库项目中建立提供程序,再在Web项目中引用所生成的DLL。这两种方法都是可行的。
这里要在Web站点项目中直接建立提供程序,所以在应用程序中创建了App_Code文件夹。在该文件夹中保存所创建的类文件,类文件就是我们要建立的提供程序。
创建好App_Code文件夹后,在该文件夹中创建一个新类,根据自己使用的语言,将该类命名为XmlMembershipProvider.vb或XmlMembershipProvider.cs。建立好这个类文件后,让XmlMembershipProvider类继承MembershipProvider,并确定要重写哪些方法和属性。为此,使用Visual Studio 2005建立该类的框架。这个过程所创建的代码如程序清单15-5所示。
程序清单15-5 XmlMembershipProvider类的开头部分
VB
Imports Microsoft.VisualBasic
Imports System.Xml
Imports System.Configuration.Provider
Imports System.Web.Hosting
Imports System.Collections
Imports System.Collections.Generic
Public Class XmlMembershipProvider
Inherits MembershipProvider
End Class
C#
using System;
using System.Web.Hosting;
using System.Web.Security;
using System.Xml;
using System.Collections.Generic;
/// <summary>
/// Summary description for XmlMembershipProvider
/// </summary>
public calss XmlMembershipProvider: MembershipProvider
{
public XmlMembershipProvider()
{
//
//TODO: Add constructor logic here
//
}
}
上面只对基类XmlMembershipProvider做了几处修改。首先,在文件中导入了一些额外的命名空间,这么做是为了在后面利用.NET的XML功能、泛型等。另外这个新类XmlMembershipProvider继承了MembershipProvider。
15.4.2 构建需要的类框架
为了让Visual Studio 2005用需要的方法和属性建立XmlMembershipProvider类,请根据自己选择的语言执行下面的步骤。如果使用的是Visual Basic,只需按下回车键。而在C#中,首先要把光标放在文档窗口的MembershipProvider实例中,从Visual Studio菜单中选择Edit | IntelliSense | Implement Abstract Class。执行上述操作后,Visual Studio的文档窗口就会显示类的全部框架代码。程序清单15-6列出了创建Visual Basic类XmlMembership Provider的代码。
程序清单15-6 Visual Studio为XmlMembershipProvider类生成的代码
VB
Imports Microsoft.VisualBasic
Imports System.Xml
Imports System.Configuration.Provider
Imports System.Web.Hosting
Imports System.Collections
Imports System.Collections.Generic
Public Class XmlMembershipProvider
Inherits MembershipProvider
Public Overrides Property ApplicationName() As String
Get
End Get
Set(ByVal value As String)
End Set
End Property
Public Overrides Function ChangePassword(ByVal username As String, _
ByVal oldPassword As String, ByVal newPassword As String) As Boolean
End Function
Public Overrides Function ChangePasswordQuestionAndAnswer(_
ByVal username As String, ByVal password As String,_
ByVal newPasswordQuestion As String, _
ByVal newPasswordAnswer As String) As Boolean
End Function
Public Overrides Function CreateUser(ByVal username As String, _
ByVal password As String, ByVal email As String,_
ByVal passwordQuestion As String, ByVal passwordAnswer As String,_
ByVal isApproved As Boolean, ByVal providerUserKey As Object,_
ByRef status As System.Web.Security.MembershipCreateStatus) As _
System.Web.Security.MembershipUser
End Function
Public Overrides Function DeleteUser(ByVal username As String, _
ByVal deleteAllRelatedData As Boolean) As Boolean
End Function
Public Overrides ReadOnly Property EnablePasswordReset () As Boolean
Get
End Get
End Property
Public Overrides ReadOnly Property EnablePasswordRetrieval() As Boolean
Get
End Get
End Property
Public Overrides Function FindUserByEmail(_
ByVal emailToMatch As String, ByVal pageIndex As Integer, _
ByVal pageSize As Integer, ByRef totalRecords As Integer) _
As System.Web.Security.MembershipUserCollection
End Function
Public Overrides Function FindUserByName(_
ByVal usernameToMatch As String, ByVal pageIndex As Integer, _
ByVal pageSize As Integer, ByRef totalRecords As Integer) _
As System.Web.Security.MembershipUserCollection
End Function
Public Overrides Function GetAllUsers(ByVal pageIndex As Integer, _
ByVal pageSize As Integer, ByRef totalRecords As Integer) _
As System.Web.Security.MembershipUserCollection
End Function
Public Overrides Function GetNumberOfUsersOnline() As Integer
End Function
Public Overrides Function GetPassword(ByVal username As String, _
ByVal answer As String) As String
End Function
Public Overloads Overrides Function GetUser(_
ByVal providerUserKey As Object, ByVal userIsOnline As Boolean)_
As System.Web.Security.MembershipUser
End Function
Public Overloads Overrides Function GetUser(_
ByVal username As String, ByVal userIsOnline As Boolean)_
As System.Web.Security.MembershipUser
End Function
Public Overrides Function GetUserNameByEmail(_
ByVal email As String) As String
End Function
Public Overrides ReadOnly Property MaxInvalidPasswordAttempts() As Integer
Get
End Get
End Property
Public Overrides ReadOnly Property MinRequiredNonAlphanumricCharacters ()
As Integer
Get
End Get
End Property
Public Overrides ReadOnly Property MinRequiredPasswordLength()
As Integer
Get
End Get
End Property
Public Overrides ReadOnly Property PasswordAttemptWindow() As Integer
Get
End Get
End Property
Public Overrides ReadOnly Property PasswordFormat()As_
System.Web.Security.MembershipPasswordFormat
Get
End Get
End Property
Public Overrides ReadOnly Property _
PasswordStrengthRegularExpression() As String
Get
End Get
End Property
Public Overrides ReadOnly Property _
RequiresQuestionAndAnswer() As Boolean
Get
End Get
End Property
Public Overrides ReadOnly Property _
RequiresUniqueEmail() As Boolean
Get
End Get
End Property
Public Overrides Function ResetPassword(ByVal username As String, _
ByVal answer As String) As String
End Function
Public Overrides Function UnlockUser(ByVal username As String) As Boolean
End Function
Public Overrides Sub UpdateUser(ByVal user As _
System.Web.Security.MembershipUser)
End Sub
Public Overrides Function ValidateUser(ByVal username As String, _
ByVal password As String) As Boolean
End Function
End Class
代码非常多!有了这个框架后,下一步应建立一些项,供所建立的提供程序使用。首先建立XML文件,它包含允许访问应用程序的所有用户。
15.4.3 创建XML用户数据库
这是一个XML成员提供程序,目的是从XML文件中读取用户信息,而不是从SQL Server等数据库中读取,所以,必须定义提供程序可以使用的XML文件结构。这个示例使用的结构如程序清单15-7所示。
程序清单15-7 用于存储用户名和密码的XML文件
<?xml version="1.0" encoding="utf-8" ?>
<Users>
<User>
<Username>BillEvjen</Username>
<Password>Bubbles</Password>
<Email>evjen@yahoo.com</Email>
<DateCreated>11/10/2005</DateCreated>
</User>
<User>
<Username>ScottHanselman</Username>
<Password>YabbaDabbaDo</Password>
<Email>123@msn.com</Email>
<DateCreated>10/20/2005</DateCreated>
</User>
<User>
<Username>DevinRader</Username>
<Password>BamBam</Password>
<Email>456@msn.com</Email>
<DateCreated>9/23/2005</DateCreated>
</User>
</Users>
这个XML文件只保存了3个用户实例,它们都包含了用户名、密码、电子邮件地址和创建用户的日期。这是一个数据文件,所以应把该文件放在ASP.NET应用程序的App_ Data文件夹中。该文件的名称可任意,这里将它命名为UserDatabase.xml。
本章的后面在验证用户时,将从这个XML文件中提取这些值。
15.4.4 在web.config文件中定义提供程序实例
第14章在配置文件(如machine.config或web.config文件)中定义了一个提供程序及其行为。这个提供程序是为一个应用程序实例定义的,所以本例在应用程序的web.config文件中定义了一个提供程序。
默认的提供程序是SqlMembershipProvider,它是在服务器的machine.config文件中定义的。对于这个示例,必须覆盖这个设置,建立一个新的默认提供程序。web.config文件中的XML成员提供程序声明如程序清单15-8所示。
程序清单15-8 在web.config文件中定义XmlMembershipProvider
<configuration>
<system.web>
<authentication mode="Forms" />
<membership defaultProvider="XmlFileProvider">
<providers>
<add name = "XmlFileProvider" type = "XmlMembershipProvider"
xmlUserDatabaseFile="~/App_Data/UserDatabase.xml" />
</providers>
</membership>
</system.web>
</configuration>
在这个程序清单中,默认的提供程序定义为XmlFileProvider。因为这个提供程序的名称没有在父配置文件中指定,所以必须在web.config文件中定义XmlFileProvider。
使用DefaultProvider属性可以定义用于成员系统的提供程序名,这里是XmlFile Provider。接着在<providers>段中用<add>元素定义XmlFileProvider实例。<add>元素为提供程序指定名称XmlFileProvider,它还指向提供程序的类(或类型),这里是刚才创建的框架类XmlMembershipProvider。这是最重要的两个属性。
除了这些属性之外,还可以在提供程序声明中创建需要的属性。但无论创建什么类型的提供程序,都必须在提供程序中指定属性,并操作通过这些属性提供的值。在简单的XmlMembershipProvider中,只有一个定制属性xmlUserDatabaseFile。它指向用户数据库XML文件的位置。对于这个提供程序而言,这是一个可选属性。如果没有为xmlUser DatabaseFile提供值,就使用默认值。在程序清单15-8中,为要使用的XML文件提供了一个值。注意xmlUserDatabaseFile只是文件名。
在该示例中没有列出属性applicationName,但它是一个可用的属性,因为它在XmlMembershipProvider类中指定。这个属性指向XmlMembershipProvider实例要定位的应用程序。其默认值也放在配置文件内这个默认提供程序的声明中,如下所示:
applicationName="/"
15.4.5 没有实现MembershipProvider类的方法和属性
下面看看XmlMembershipProvider类。下一步是实现提供程序需要的方法或属性。不需要实际使用这个框架包含的方法,只需扩展感兴趣的方法。例如,如果不允许通过编程访问的方式改变密码(这会改变使用该编程访问的控件),可以不执行某个动作,如果有人试图实现该方法,就会抛出一个异常,如程序清单15-9所示。
程序清单15-9 通过抛出异常,不实现某个可用的方法
VB
Public Overrides Function ChangePassword(ByVal username As String, _
ByVal oldPassword As String, ByVal newPassword As String) As Boolean
Throw New NotSupportedException()
End Function
C#
public override bool ChangePassword(string username,
string oldPassword, string newPassword)
{
throw new NotSupportException();
}
如果调用了ChangePassword()方法,就会抛出一个NotSupportException异常。如果不想抛出异常,可以返回false值,不执行其他操作(但这会使试图实现该方法的开发人员感到困惑,不理解该方法的底层逻辑)。如程序清单15-10所示。
程序清单15-10 通过返回false值,不实现某个可用的方法
VB
Public Overrides Function ChangePassword(ByVal username As String, _
ByVal oldPassword As String, ByVal newPassword As String) As Boolean
Return False
End Function
C#
public override bool ChangePassword(string username,
string oldPassword, string newPassword)
{
return false;
}
本章不打算介绍XmlMembershipProvider的每个操作,因此,读者可以自己试着使用MembershipProvider派生实例的可用方法和属性,对不打算使用的项进行必要的修改。
15.4.6 实现MembershipProvider类的方法和属性
下面该介绍一下实现MembershipProvider类的一些方法和属性,以使XmlMembershipProvider类能够发挥作用。首先要建立一些私有变量,供类中的多个方法使用。这些变量声明如程序清单15-11所示。
程序清单15-11 在XmlMembershipProvider类中声明一些私有变量
VB
Public Class XmlMembershipProvider
Inherit MembershipProvider
Private _AppName As String
Private _MyUsers As Dictionary(Of String, MembershipUser)
Private _FileName As String
'Code removed for clarity
End Class
C#
public class XmlMembershipProvider: MembershipProvider
{
Private string _AppName;
Private Dictionary<string, MembershipUser> _MyUsers;
Private string _FileName;
'Code removed for clarity
}
上面声明的变量是类中多个方法需要的变量。_AppName变量定义了使用XML成员提供程序的应用程序,在本例中,它是本地应用程序。XML文件中所有的成员都放在某种类型的集合中,这个例子使用字典泛型类型_MyUsers。最后,这个示例用_FileName变量指向要使用的文件。
1. ApplicationName属性
定义了私有变量后,下一步就定义ApplicationName属性。这里要使用私有变量_AppName。ApplicationName的属性定义如程序清单15-12所示。
程序清单15-12 定义ApplicationName属性
VB
Public Overrides Property ApplicationName() As String
Get
Return _AppName
End Get
Set(ByVal value As String)
_AppName = value
End Set
End Property
C#
public override string ApplicationName
{
get
{
return _AppName;
}
set
{
_AppName = value;
}
}
定义了ApplicationName属性后,就要在web.config文件的提供程序声明(XmlFileProvider)中检索已定义的值。
2. 扩展Initialize()方法
现在扩展Initialize()方法,使它在web.config文件的提供程序声明中读取定制属性及其值。在XmlMembershipProvider类的框架代码中,注意Initialize()方法没有包含在可选项的列表中。
在第一次初始化提供程序时,会调用Initialize()方法。不需要重写这个方法,因此,在类框架的声明中没有包含它。为了把Initialize()方法放在XmlMembershipProvider类中,只需在类中输入Public Overrides(Visual Basic代码)或public overrides(C#代码),然后通过IntelliSense打开Initialize()方法,如图15-5所示。

图 15-5
以这种方式将Initialize()方法放在类中是非常简单的。从IntelliSense的列表中选择Initialize()方法,按下回车键,就会在代码中显示该方法的基本构建代码,如程序清单15-13所示。
程序清单15-13 Initialize()方法的开头部分
VB
Public Overrides Sub Initialize(ByVal name As String, _
ByVal config As System.Collections.Specialized.NameValueCollection)
MyBase.Initialize(name, config)
End Sub
C#
public override void Initialize(string name,
System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
}
Initialize()方法带有两个参数。第一个参数是参数名,第二个参数是web.config文件的提供程序声明中的名称/值对,其中包括所有的属性及其值,例如xmlUserDatabaseFile属性及包含用户信息的XML文件名。使用config可以访问这些定义好的值。
在XmlFileProvider实例中,包含了applicationName属性和xmlUserDatabaseFile属性,如程序清单15-14所示。
程序清单15-14 扩展Initialize()方法
VB
Public Overrides Sub Initialize(ByVal name As String, _
ByVal config As System.Collections.Specialized.NameValueCollection)
MyBase.Initialize(name, config)
_AppName = config("applicationName")
If (String.IsNullOrEmpty(_AppName)) Then
_AppName = "/"
End If
_FileName = config("xmlUserDatabaseFile")
If (String.IsNullOrEmpty(_FileName)) Then
_FileName = "~/App_Data/Users.xml"
End If
End Sub
C#
public override void Initialize(string name,
System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
_AppName = config["applicationName"];
if (String.IsNullOrEmpty(_AppName))
{
_AppName = "/";
}
_FileName = config["xmlUserDatabaseFile"];
if (String.IsNullOrEmpty(_FileName))
{
_FileName = "~/App_Data/Users.xml";
}
}
上面的代码除了使用MyBase.Initialize()方法执行初始化操作之外,还用config检索applicationName属性和xmlUserDatabaseFile属性的值。无论如何都应先检查属性值是否为空。如果在web.config文件的提供程序声明中没有指定这些属性,就用String.IsNullOr Empty()方法给它们赋予默认值。在XmlFileProvider实例中,就是这种情况。因为实际上没有声明XmlFileProvider声明中的applicationName属性,所以把默认值“/”赋予它。
xmlUserDatabaseFile属性有一个值。如果没有在web.config文件中给它赋值,提供程序就会在App_Data文件夹中查找XML文件Users.xml。
3. 验证用户
成员提供程序的一个很重要的功能就是验证用户(即检查用户的身份)。用户的验证是通过ASP.NET服务器控件Login实现的。这个控件利用了Membership.ValidateUser()方法,而该方法又利用了MembershipProvider类中的ValidateUser方法。
建立了Initialize()方法和私有变量后,就可以为提供程序编写一些功能了。ValidateUser()方法的实现代码如程序清单15-15所示。
程序清单15-15 实现ValidateUser()方法
VB
Public Overrides Function ValidateUser(ByVal username As String, _
ByVal password As String) As Boolean
If (String.IsNullOrEmpty(username) or String.IsNullOrEmpty(password)) Then
Return False
End If
Try
ReadUserFile()
Dim mu As MembershipUser
If (_MyUsers.TryGetValue(username.ToLower(), mu)) Then
If (mu.Comment = password) Then
Return True
End If
End If
Return False
Catch ex As Exception
Throw New Exception(ex.Message.ToString())
End Try
End Function
C#
public override bool ValidateUser(string username, string password)
{
If (String.IsNullOrEmpty(username) ||
String.IsNullOrEmpty(password))
{
return false;
}
try
{
ReadUserFile();
MembershipUser mu;
If (_MyUsers.TryGetValue(username.ToLower(), out mu))
{
If (mu.Comment = password)
{
return true;
}
}
return false;
}
catch (Exception ex)
{
throw new Exception(ex.Message.ToString());
}
}
ValidateUser()方法带有两个参数:用户名和用户的密码(它们的类型都是String)。ValidateUser()方法返回的值是Boolean类型:即True或False,表示验证过程是否成功完成。
在ValidateUser()方法中,首先进行检查,以确定是否在请求中遗漏了用户名或密码。如果是,就返回False值。
如果在XML文件中包含了用户名和密码,就进入Try Catch块。从XML文件中把用户信息读入MyUsers变量中的过程是由ReadUserFile()方法完成的。这个方法稍后探讨,但注意_MyUsers变量是Dictionary泛型类的一个实例。其关键是用户名的小写字符串值,该值的类型是MembershipUser,这是通过成员系统提供的类型。
用XML文件中的所有用户填充_MyUsers对象后,就创建了一个MembershipUser实例。这个对象是TryGetValue操作的结果。MembershipUser不包含用户的密码,所以,ReadUserFile()方法把用户的密码赋予MembershipUser类的Comment属性值。如果在字典集合中找到了用户名,该MembershipUser实例的密码就与Comment属性值进行比较。如果它们相同,ValidateUser()方法的返回值就是True。
可以看出,这个方法依赖于ReadUserFile()方法的结果。下面就讨论ReadUserFile()方法。
4. 建立ReadUserFile()方法
ReadUserFile()方法读取XML文件的内容,而XML文件包含应用程序的所有用户。这是一个定制方法,其工作在ValidateUser()方法的外部完成。也就是说,ReadUserFile()方法可以在其他方法(如GetAllUsers()方法)中重用。ReadUserFile()方法只是读取XML文件的内容,把所有的用户放在_MyUsers变量中,如程序清单15-16所示。
程序清单15-16 ReadUserFile()方法获取应用程序的所有用户
VB
Private Sub ReadUserFile()
SyncLock(Me)
If (_MyUsers Is Nothing) Then
_MyUsers = New Dictionary(Of String, MembershipUser)()
Dim xd As XmlDocument = New XmlDocument()
Xd.Load(HostingEnvironment.MapPath(_FileName))
Dim xnl As XmlNodeList = xd.GetElementsByTagName("User")
For Each node As XmlNode In xnl
Dim mu As MembershipUser=New MembershipUser(Name, _
node("Username").InnerText, _
Nothing, _
node("Email").InnerText, _
String.Empty,_
node("Password").InnerText, _
True, _
False, _
DateTime.Parse(node("DateCreated").InnerText), _
DateTime.Now, _
DateTime.Now, _
DateTime.Now, _
DateTime.Now)
_MyUsers.Add(mu.UserName.ToLower(), mu)
Next
End If
End SyncLock
End Sub
C#
private void ReadUserFile()
{
lock(this)
{
if (_MyUsers ==null)
{
_MyUsers = new Dictionary<string, MembershipUser>();
XmlDocument xd = new XmlDocument();
Xd.Load(HostingEnvironment.MapPath(_FileName));
XmlNodeList xnl = xd.GetElementsByTagName("User");
foreach (XmlNode node in xnl){
{
MembershipUser mu = MembershipUser(Name,
node["Username"].InnerText,
null,
node["Email"].InnerText,
String.Empty,
node["Password"].InnerText,
true,
false,
DateTime.Parse(node["DateCreated"].InnerText),
DateTime.Now,
DateTime.Now,
DateTime.Now,
DateTime.Now);
_MyUsers.Add(mu.UserName.ToLower(), mu);
}
}
}
}
ReadUserFile()方法首先在所运行的线程上锁定要执行的操作。这是ASP.NET的一个独特功能。在编写自己的提供程序时,一定要使用线程安全的代码。对于在ASP.NET中编写的大多数项,如HttpModule或HttpHandler(详见第26章),都不需要使用线程安全的代码。这些项可能在多个线程上有多个请求,每个向HttpModule或HttpHandler发出请求的线程都有这些项的唯一实例。
与HttpHandler不同,ASP.NET应用程序仅创建和使用提供程序的一个实例。如果向应用程序发出了多个请求,所有这些线程都将试图访问应用程序所包含的唯一提供程序实例。多个请求有可能同时访问提供程序实例,所以应以线程安全的方式创建提供程序。在执行文件I/O操作等任务时,使用锁定操作就可以达到上述目的。这就是在ReadUserFile()方法中使用SyncLock(Visual Basic)或lock(C#)语句的原因。
其优点是在应用程序中只运行一个提供程序实例。用XML文件的内容填充了_MyUsers变量后,就不需要重新填充该对象。给请求者发送响应后,提供程序实例不会消失,而是包含在内存中,供多个请求使用。这就是在读取XML文件之前,检查_MyUsers是否包含值的原因。
如果_MyUsers为空,就使用XmlDocument对象获取文档中的每个<User>元素。对于文档中的每个<User>元素,把值赋予一个MembershipUser实例。该MembershipUser对象带有如下参数:
MembershipUser(
providerName As String, _
name As String, _
providerUserKey As Object, _
email As String, _
passwordQuestion As String, _
comment As String, _
isApproved As Boolean, _
isLockedOut As Boolean, _
creationDate As DateTime, _
lastLoginDate As DateTime, _
lastActivityDate As DateTime, _
lastPasswordChangedDate As DateTime, _
lastLockoutDate As DateTime)
在这个构造函数中,我们并没有为每一项提供值,构造函数需要的值是使用XmlNode对象从XML文件中获取的。在MembershipUser对象填充了需要的值后,就使用下面的语句将其添加到_MyUsers对象中:
_MyUsers.Add(mu.UserName.ToLower(), mu)
建立了ReadUserFile()方法后,就可以在ValidateUser()方法和其他方法中使用它了。一旦填充了_MyUsers集合,就不需要再次填充它,其他方法仍可以使用它。下面探讨如何在ASP.NET应用程序中使用前面演示的提供程序。
15.4.7 使用XmlMembershipProvider进行用户登录
如果读者按照本章前面的步骤完成了示例,使用XmlMembershipProvider就不需要做太多的工作。现在应有一个XML数据文件,它包含了应用程序的所有用户(关于这个文件请参阅程序清单15-7),在应用程序的web.config文件中还包含XmlFileProvider的声明(对web.config文件的修改参见程序清单15-8)。当然,另一个必须有的项是应用程序的App_Code文件夹中的XmlMembershipProvider.vb或.cs类。但如果把提供程序建立为类库,就要确保在ASP.NET应用程序中正确引用所创建的DLL(即DLL在Bin文件夹中)。有了这些后,使用提供程序就很简单了。
下面举一个简单的例子。创建一个Default.aspx页面,它只包含文本“You are authenticated!”
接着,创建Login.aspx页面,在该页面上拖放一个Login服务器控件。不需要对Login.aspx页面做其他修改。用户现在就可以登录到应用程序上了。
提示:
有关成员系统的详细信息,可参阅第18章,其中包括了成员系统中各个服务器控件的介绍。
在微型ASP.NET应用程序中有了这两个文件后,就要对web.config文件进行一些小的修改,以允许使用Forms验证方式,拒绝浏览任意页面的所有匿名用户。代码如程序清单15-17所示。
程序清单15-17 在web.config文件中拒绝浏览应用程序的匿名用户
<configuration>
<system.web>
<authentication mode="Forms" />
<authorization>
<deny users="?" />
</authorization>
<!-- other settings removed for clarity -->
</system.web>
</configuration>
现在运行Default.aspx页面,会立即转向Login.aspx页面(应在应用程序中创建这个文件,它只包含一个Login服务器控件)。在该页面上,输入XML文件中的一个用户名和密码。
对于ASP.NET 2.0中的基于提供程序的新模型,一个优点是使用提供程序的控件并不知道对底层提供程序的这些修改。在这个例子中,删除了默认的SqlMembershipProvider,代之以只读的XML提供程序,Login服务器控件对此一无所知。当终端用户单击Login服务器控件中的Log In按钮时,该控件仍利用Membership.ValidateUser()方法,而该方法利用了刚才创建的XmlMembershipProvider。显然,这是一个很强大的模型。







