前述文章: TheBeerHouse 网站项目学习笔记(1)----换肤技术
必备知识文章:ASP.NET 2.0下实现匿名用户向注册用户的迁移(上)
ASP.NET 2.0下实现匿名用户向注册用户的迁移(下)
上篇讨论了换肤技术,这篇将继续讨论下一个知识点----个性化管理,即利用ASP.NET 2.0 内置的用户个性化管理功能(必备文章讨论)将用户的各种个性信息存入自定义数据库,以达到个性信息的"记忆"功能,让每个用户无论是匿名还是注册,在他们下次登录或匿名登录后仍然能得到自己上次的个性设置(比如网站皮肤,页面布局,注册时的各种个人信息等).
这里的个性化管理还包括权限管理的说明(第3篇讨论),其技术基础请参看上述必备知识文章.
那么我们就继续展开讨论.
一. 数据讨论
确保此网站所用到的数据库是自定义的,而不是自动生成的,如下图:
确保此目录是空的,而且已经如
http://www.cnblogs.com/Rogerliu/archive/2008/08/30/1279847.html文章介绍过做过数据库迁移工作了.
下面我们以一个现象出发讨论个性化管理.(注意:我们现在使用的示例代码是该网站配套书在Wrox网站上提供的前五章的源代码,因此,我们看到的界面还比较单调,但不影响我们对下面功能的讨论)
做好了数据库迁移工作(如果需要的话)并在Web.Config文件中修改了数据库配置后,运行网站,如下两幅图进行换肤前后的对比:
打开数据库,找到相应的数据库文件ASPNETDB,在此数据库中进行如下查询:
select userid,username,isanonymous,lastactivitydate
from aspnet_users
order by lastactivitydate desc
得到如下结果:
发现此匿名用户最后活动的时间就是刚才登录后并更改皮肤的时间(发现总有八个小时的差距,时区关系?有待考证),ASPNETD数据库中个性化设置相关表的说明,请查看如下文章:http://www.cnblogs.com/Rogerliu/archive/2008/08/30/1279847.html, 因为 isanonymous=1 ,注意此时用户名是系统自动分配的,所以我们此时运行的身份是匿名用户,当我们用超级用户/密码(admin/admin)登录后,发现此时上述查询结果会变成如下图所示:
发现刚才匿名登录的用户如果注册成功后,会多了一个注册用户Admin,最后活动时间为登录时间 ,这之间的关系已经在匿名用户迁移相关文章中介绍过了,这里不再强调了.
那么上述现象就是:如果匿名用户登录后,做的任何个性化设置(例如换肤),都会在数据库中得到记录,以便在下次登录后去加载上次"记忆"的个性设置,得到上次自己配置的个性皮肤,即使上次是匿名登录,这正是各大商业网站匿名购物车记录的原理.既然匿名用户可以,那么注册用户当然也是可以的.
其实这些技术在匿名用户迁移的两篇文章中都详细介绍了,这里就不再强调了,可能我们感到理解比较困难的地方就是BasePage.cs类中如下语句的作用:
this.Theme = (HttpContext.Current.Profile as ProfileCommon).Preferences.Theme;
也正是这条语句加载了上次存入的个性设置,那么关键就是 Profile类(必备文章介绍过) 的作用,谈到这个类就进入如下的讨论,先从Web.Config开始讨论.
二.Web.Config中有关个性化设置节的讨论
1. <configSections> 和 <theBeerHouse> 配置节说明
这两个配置节关系比较紧密,所以放到一起讲解.
<configSections>
<section name="theBeerHouse" type="MB.TheBeerHouse.TheBeerHouseSection, __code"/>
</configSections>
关于ConfigSections配置节的详细说明请参考如下地址:http://msdn.microsoft.com/zh-cn/library/ms228256(VS.80).aspx
这个配置节有三个属性,其中theBeerHouse直接决定下面<theBeerHouse>配置节的名称, MB.TheBeerHouse.TheBeerHouseSection 映射到ConfigSection.cs 这个类文件中的TheBeerHouseSection类,查看这个文件的命名空间,就可以知道为什么可以这么映射以及这么映射的用意是什么.
<theBeerHouse>
<contactForm mailTo="******@****.com"/>
<articles pageSize="10" />
</theBeerHouse>
theBeerHouse配置节中目前有两个子节点,这两个子节点分别映射到如下ConfigSection.cs中的黄色高亮部分属性:
其实我们看到,这两个属性都有 IsRequired = true 的说明,那么这个说明表示此属性是必须的,因为它们在Web.config配置节
中都定义过,而其它的两个属性都没有 IsRequired = true 的说明,只有默认值的说明.那么这两个配置节就是对 ConfigurationSection 类
的扩展,以便在今后使用.
注意:上面代码中两个粗红体的类 ContactFormElement 和 ArticlesElement 分别又是在同一个 ConfigSection.cs文件中定义的(如下代码):
这里只罗列ContactFormElement 类,ArticlesElement 是一样的道理.它们提供了Web.config中两个子节点 contactForm 和 ArticlesElement 映射的属性 ContactForm 和 Articles各自的类型,这么说有些绕口,有些难理解,那么请看如下Contact.aspx.cs页面的后台对这个属性的引用:
Globals.Settings.ContactForm.MailTo
Globals.Settings.ContactForm.MailCC
Globals.Settings.ContactForm 返回 TheBeerHouseSection 下的属性ContactForm,而这个属性的类型是由ContactFormElement这个类定义的,这就是它们之间的关系.上述关系弄清楚是我们理解个性化设置的关键.
上述配置节映射到类属性的用意就是存储各种个性化信息到数据库,然后再配合配置节<Profile>(下面介绍)就能完全控制匿名用户或注册用户的个性"记忆"功能.
通过Web.config的配置节进行声明各种个性类别,然而需要提供API对这些配置节进行访问,幸好MS为我们提供了ConfigurationSection这个类,让我们能灵活控制配置节并用编码方式访问.
2. <profile>配置节概述
说它是概述,那是因为我们在本篇文章的开始提过的必备知识文章中对其进行了详细讨论,这里就介绍起关联关系就可以了.
Web.config中整个 <system.web>......</system.web> 内容比较多,总体来说就是
(1)利用ASP.NET 2.0 内置的用户个性化管理功能(必备文章讨论)将用户的各种个性信息存入自定义数据库,以达到个性信息的"记忆"功能,让每个用户无论是匿名还是注册,在他们下次登录或匿名登录后仍然能得到自己上次的个性设置(比如网站皮肤,页面布局,注册时的各种个人信息等).
(2)匿名用户的管理
(3)注册用户的角色权限管理,即什么页面什么用户能访问的问题,或什么功能什么用户能使用的问题.
三. 个性信息的加载和保存
上述讨论的两个论点都是为个性信息做的准备,具体代码运行的过程还是有必要解释一二的.
当我们单击主页右上注册按钮后,会进入Register.aspx页面,这个页面除了使用母版页外,还使用了UserProfile.ascx这个用户控件,那么个性信息的存储读取全在此页面的后台代码实现.
此页面Page_Load事件和SaveProfile事件完成对个性化信息的加载和读取工作.还是以流程变化来说明情况:
1. 先注册一个用户,这里我们注册一个名为 "martin" 密码为 "martin/"的用户,注意注册页面是使用了MS提供的服务器控件CreateUserWizard,这个控件可以协助并提示我们完成用户的注册任务,具体实现见代码,页面如下图:
当我们注册成功后,信息会反映到数据库中,若使用如下语句就可以如下图:
select userid,username,isanonymous,lastactivitydate
from aspnet_users
order by lastactivitydate desc
此时该注册用户最后活动的时间就是刚刚注册的时间.
2.完成注册后,进入如下页面:
此页面就是设置注册用户的个性化信息的界面,随便填入信息,开始随便填写,比如就填写某部分就可以了:
language:English Gender:Female Occupation:Artist country:China ,我们就注册如下四条信息,看看在数据库中又会发生什么变化
select userid,username,isanonymous,lastactivitydate
from aspnet_users
order by lastactivitydate desc
select userid,propertynames,propertyvaluesstring,lastupdateddate
from aspnet_profile
order by lastupdateddate desc
如上图: 通过上面两条命令我们可以看到,刚才定义的个人信息是保存在aspnet_profile表中的,而且值得更进一步探究的就是这些个性的值是如何保存的,那么奥秘就在上述虚线方框的两个字段中,我们把这两个字段copy出来看看:
propertynames :Website:S:0:0:Contacts.Fax:S:0:0:FirstName:S:0:0:Gender:S:0:1:Address.City:S:1:0:LastName:S:1:0:
Preferences.Newsletter:S:1:82:Address.Street:S:83:0:Forum.Signature:S:83:0:Forum.AvatarUrl:S:83:0:
Address.Country:S:83:5:Occupation:S:88:6:Contacts.Phone:S:94:0:Preferences.Culture:S:94:5:
Address.PostalCode:S:99:0:Address.State:S:99:0:
propertyvaluesstring:F<?xml version="1.0" encoding="utf-16"?> <SubscriptionType>None</SubscriptionType>ChinaArtisten-US
上面看似唬人,我们来分析其关系. propertynames字段记录着所有用户应该具有的个性项目,这些项目都是和Web.Config中节点对应的,这个字段还存储了另外一个信息,那就是这些个性信息如果存在于Propertyvaluesstring中,那么在其中存储的起始位置和结束位置是什么,细看上述两个字段值中相同颜色文字之间的对应关系就一目了然了.
其实,众多的个性信息就存储在了两个互相配合的字段:propertynames 和 propertyvaluesstring中.
至此:个性化信息管理原理就介绍至此,我们也从数据库的变化角度观察了其原理,有助于我们理解什么是ASP.NET 2.0的自动用户个性管理.
再次强调:这些介绍并没有分析各种源代码,而是讲解关键技术的原理.我个人认为,在理解支撑功能的各个页面运行流程关系和数据发生的变化后,有了一个大致的框架认识后,再去深入到后台理解源代码是合适的,其实源代码的类与类之间的关系在本网站里也是需要花功夫理解的,那么会在后续再介绍.
还想强调:我们的分析仍然是面向应用的,而支撑这些应用的理论,例如OOP一大套理论思想,甚至设计模式(本网站也应用了某些设计模式)都是不可回避的.那是因为后期理解类和类之间的关系时,这些理论一定会涉及到.