ASPNETDB 这个隐藏在ASP.NET 2.0四大“插件”(SqlMembershipProvider、SqlRoleProvider、SqlProfileProvider、 SqlPersonalizationProvider)之后,时不时在你App_Data目录下幽灵般出现的SQL数据库,其实也并没什么神奇之处,我等凡夫俗子进去一看,原来也不过如此。不过如果我们要编写自定义Provider的话,还是得仔细研究一下下的,因为这4个Provider大部分的业务逻辑还是“封装”在这个数据库里的。 下面,就容我这个老小弟,为各位兄弟理出里面的表、视图和存储过程。

   ASPNETDB 这个隐藏在ASP.NET 2.0四大“插件”(SqlMembershipProvider、SqlRoleProvider、SqlProfileProvider、    SqlPersonalizationProvider)之后,时不时在你App_Data目录下幽灵般出现的SQL数据库,其实也并没什么神奇之处,我等凡夫俗子进去一看,原来也不过如此。不过如果我们要编写自定义Provider的话,还是得仔细研究一下下的,因为这4个Provider大部分的业务逻辑还是“封装”在这个数据库里的。
    下面,就容我这个老小弟,为各位兄弟理出里面的表、视图和存储过程。
    
    注:其实还有SqlWebEventProvider,它用到表aspnet_WebEvent_Events和存储过程aspnet_WebEvent_LogEvent。
    因为老小弟认为从性能上考虑,写入本地文件是更好的选择,所以在此不作介绍。
    另外,还有个和ASPNETDB无关的SiteMapProvider,主要配合SiteMapPath 等控件,一般以Xml文件形式存放站点地图。

    看张“地图”先:

    数据库关系图

SQL server数据库部门表 sql数据库表关系图_ide


这张图还是蛮重要的,兄弟们在看后面的内容时,还是要常回来看看,回来看看。

    

     在ASPNETDB数据库的几个表中,都有名称为Lowered***的字段,这些字段用来存放***字符串字段的小写形式副本。因为这些***字符串字段的比较都是不区分大小写,在表中存放一个小写形式副本,能提高字符串比较的速度。

   

     基本表 aspnet_Application、aspnet_Users


    1.应用程序表

SQL server数据库部门表 sql数据库表关系图_字段_02



    每个Provider都有一个ApplicationName属性,该属性一般定义在web.config中。举一个ProfileProvider的例子(其余3个Provider也一样):SQL server数据库部门表 sql数据库表关系图_字段_03SQL server数据库部门表 sql数据库表关系图_SQL server数据库部门表_04Web.Config

SQL server数据库部门表 sql数据库表关系图_ide_05

<system.web>
  

  <connectionStrings>
    <add name="SqlSrvConnectionString" cnotallow="
"/>
  </connectionStrings>
  

  <profile defaultProvider="SqlSrvProfileProvider">
     <providers>
      <add name="SqlSrvProfileProvider"
        type="System.Web.Security.SqlProfileProvider"
        cnotallow="SqlSrvConnectionString" 
        applicatinotallow="WebShop" 
        commandTimeout="30" 
        descriptinotallow="SqlSrvProfileProvider" />
     </providers>
    <properties>
      

    </properties>
  </profile>

  

SQL server数据库部门表 sql数据库表关系图_数据库_06


SQL server数据库部门表 sql数据库表关系图_ide_05

</system.web>    这样你就为你的应用程序注册了一个"WebShop"名称(也可以不明确配置applicationName值,默认为应用程序的虚拟根路径,即"/")。要注意的是如果你那天把"WebShop"改成了"WebShop1"(改成"webshop"、"webShop"等就和没改一样,因为应用程序名称是不区分大小写的),你以前的用户自定义属性值就人间蒸发了,因为ProfileProvider把"WebShop1"当作一个新的应用程序又新注册了一遍(这时候看过我这篇文章的兄弟就该知道怎么办了,哈哈)。

    那4个Provider是否一定要配置成同样的applicationName呢?当然不必要啦!你为每个Provider各建一个数据库都没有关系,何况区区applicationName值呢。不过在此老小弟建议各位兄弟,别没事找事,还是取一样的名称好。


    2.基本用户表

SQL server数据库部门表 sql数据库表关系图_SQL server数据库部门表_08



    表中MobileAlias字段(以及用户成员资格表aspnet_MemberShip中的MobilePIN字段),没见在那里用到。老小弟猜想微软这样做有两种可能:一种是想以后帐户和手机绑定,另一种可能就是为手机上网而预留的。

    不知各位DBA兄弟有没看出这个表与它的几个从表的关系,有点不太“讲道理”,居然有2个一对一的关系。“为什么不合并?不知道第3范式啊?”,老小弟以前想装文化人的时候,总是这样吓唬小小弟的。若干年后,当老小弟看了几本架构/模式的书,自我扫盲之后,才知道其实这是ORM模式中的一种。

    另外,微软工程师这样设计还是非常巧妙的。在将公有部分提成几张基本表后,数据库关系图4个部分就可合可分了。你可以试着在数据库关系图盖掉某几个部分,剩下的部分仍然能够成一个完整的系统。

    最后再交待一下IsAnonymous和LastActivityDate两个字段。因为个性化用户配置和页面个性化设置能够支持匿名用户,所以该表中也会存在匿名用户,IsAnonymous字段就是指示用户是否为匿名用户的标志字段。LastActivityDate字段记录用户最后活动时间。该字段十分重要,每次成功的操作都会更新它,同时它也是判断用户是否为非活动用户的依据之一。很多存储过程都会用到它。

     在分块描述4大部分之前,先容我简单地介绍一下两个独立的表:

     aspnet_WebEvent_Events表:记录数据操作的事件日志(可由SqlWebEventProvider启用)。

     aspnet_SchemaVersions表:

SQL server数据库部门表 sql数据库表关系图_ide_09

     

     把它的内容贴出来,各位一看就知道了。原来是微软为数据库中的各个部分设置的版本号。

用户成员资格表

SQL server数据库部门表 sql数据库表关系图_数据库_10


    相信各位兄弟看了上面这张表,对大部分字段的意思都已了然于胸了。老小弟在此只为大家理一理剩下的“小部分字段”:              

    1.PasswordFormat:密码格式?其实是密码加密方式,其.NET类型为MembershipPasswordFormat枚举。下面列出MembershipPasswordFormat 枚举的3个值:

    Clear          不加密;

    Encrypted   使用web.config中machineKey指定的方法加密/解密;

    Hashed       使用单向 Salted 哈希技术进行加密(注意是单向加密,所以密码是无法检索的)。

    PasswordSalt:上面提到单向 Salted 哈希技术在加密时会随机生成一个Salt,该字段就是存放这个Salt值的。


    2.MobilePIN:手机PIN码,现在还不知道有什么用。参见基本用户表(aspnet_Users)中的MobileAlias字段。

 

    3.IsApproved:微软的定义是:表示是否可以对成员资格用户进行身份验证。

    我的理解是:是否对用户启用成员资格身份验证,在设置为不启用的情况下(其实就是禁用),即使用户提供了正确的用户名和密码也是无法成功登录的。


    4.FailedPasswordAttemptCount:连续登录失败的次数(用户名正确,密码无效),和web.config中设置的maxInvalidPasswordAttempts值相比较决定是否锁定用户成员资格帐户。       

    FailedPasswordAttemptWindowStart:记录首次登录失败的时间。

    5.FailedPasswordAnswerAttemptCount:连续回答密码问题失败的次数。
    FailedPasswordAnswerAttemptWindowStart :记录首次失败的时间,和web.config中设置的passwordAttemptWindow值相比较决定是否锁定用户成员资格帐户。

    下面再贴出web.config中有关用户成员资格的片段,所有以颜色Fuchsia标注的都是SqlMembershipProvider的属性。

SQL server数据库部门表 sql数据库表关系图_字段_03SQL server数据库部门表 sql数据库表关系图_SQL server数据库部门表_04Web.Config

SQL server数据库部门表 sql数据库表关系图_ide_05

<system.web>
  

  <machineKey
     validatinotallow="AutoGenerate,IsolateApps"
     decryptinotallow="AutoGenerate,IsolateApps" 
     validatinotallow="SHA1" 
  />
  

  <connectionStrings>
    <add name="SqlSrvConnectionString" cnotallow="
"/>
  </connectionStrings>
  

  <membership defaultProvider="SqlSrvMembershipProvider"> 
    <providers>
      <add name="SqlSrvMembershipProvider" 
        type="System.Web.Security.SqlMembershipProvider"
        cnotallow="SqlSrvConnectionString" 
        applicatinotallow="WebShop" 
        commandTimeout="30" 
        descriptinotallow="SqlSrvMembershipProvider"
        enablePasswordRetrieval="false"
        enablePasswordReset="true"
        requiresQuestinotallow="true"
        requiresUniqueEmail="false"
        passwordFormat="Hashed"
        maxInvalidPasswordAttempts="5"
        passwordAttemptWindow="10"
        minRequiredPasswordLength="6"
        minRequiredNonalphanumericCharacters="0"
        passwordStrengthRegularExpressinotallow=""/>
   </providers>
  </membership>

SQL server数据库部门表 sql数据库表关系图_ide_05

</system.web>    角色表

SQL server数据库部门表 sql数据库表关系图_ide_15



    用户与角色关联表

SQL server数据库部门表 sql数据库表关系图_ide_16


    上面两个有关角色管理的表,更是一目了然。如果要多说几句的话,那就是通过aspnet_UsersInRoles这个关联表把用户表和角色表之间的多对多关系转化为两个一对多的关系,而这正是关系数据库所要求的。

    特别注意,如果你要为你的用户添加角色管理,在web.config中必须显式启用(enabled="true"),在默认情况下,用户角色是不启用。

web.config片段:

<system.web>

  ...

  <roleManager enabled="true">

    ...

  <roleManager/>

  ...

</system.web>

   个性化用户配置(用户自定义属性)表

SQL server数据库部门表 sql数据库表关系图_SQL server数据库部门表_17



    由此表结构可以看出,所有的用户自定义属性最后都是“打包”(序列化)成一个或两个数据块,存放在PropertyValuesString(序列化为string、Xml) 和(或) PropertyValuesBinary(序列化为Binary)两个(或其中之一)字段中,因此要求用户自定义属性必须支持序列化。

    序列化方式可由web.config中的serializeAs指定,SqlProfileProvider默认序列化方式为String。

    例如用户在web.config中配置了如下自定义属性,这里的serializeAs="String" 仅仅为了表示可以用户可以自行指定序列化方式,写不写是一个样的:SQL server数据库部门表 sql数据库表关系图_字段_03SQL server数据库部门表 sql数据库表关系图_SQL server数据库部门表_04Web.Config

SQL server数据库部门表 sql数据库表关系图_ide_05

<system.web>
  

  <connectionStrings>
    <add name="SqlSrvConnectionString" cnotallow="
"/>
  </connectionStrings>
  

  <profile defaultProvider="SqlSrvProfileProvider">
     <providers>
       

         </providers>
    <properties>
         <add name="ThemeName" type="System.String"serializeAs="String" />
         <group name="addPersonalInfo">
             <add name="FirstName" type="System.String"serializeAs="String" />
             <add name="LastName" type="System.String"serializeAs="String"  />
            <add name="Birthday" type="System.DateTime"serializeAs="String" />
         </group>
      </properties>
  </profile>

  

SQL server数据库部门表 sql数据库表关系图_数据库_06


SQL server数据库部门表 sql数据库表关系图_ide_05

</system.web>    并运行了aspx页面中的以下C#代码:

this.Profile.ThemeName = "Blue"; 
    this.Profile.PersonalInfo.FirstName = "John"; 
    this.Profile.PersonalInfo.LastName = "Smith"; 
    this.Profile.PersonalInfo.Birthday = new DateTime(1970, 11, 22);

    然后打开数据库中的aspnet_Profile查看表,两个字段的内容分别为:

PropertyNames:"PersonalInfo.FirstName:S:0:4:PersonalInfo.Birthday:S:4:81:PersonalInfo.LastName:S:85:5:ThemeName:S:90:4:"

PropertyValuesString:"John 1970-11-22T00:00:00SmithBlue"

注:以后在实现自定义用户配置提供程序(ProfileProvider) 一文中我会更详尽地讨论。


    有关页面个性化设置的3个表

    关系图

SQL server数据库部门表 sql数据库表关系图_数据库_23



    页面路径(地址)表

SQL server数据库部门表 sql数据库表关系图_字段_24



处于共享范围(Shared Scope)的页面个性化设置表

SQL server数据库部门表 sql数据库表关系图_字段_25



处于单用户范围(User Scope)的页面个性化设置表

SQL server数据库部门表 sql数据库表关系图_字段_26



    视图

    1.aspnet_Applications表的全表视图。

    vw_aspnet_Applications


    2.aspnet_Membership表与aspnet_Users表的关联视图

    vw_aspnet_MembershipUsers

   

    3.返回aspnet_Profiles表的用户ID、上次修改时间和属性名称串、字符串属性值、二进制属性值的总长度

    vw_aspnet_Profiles


    4.aspnet_Roles表的全表视图。

    vw_aspnet_Roles


    5.aspnet_Users表的全表视图。

    vw_aspnet_Users


    6.aspnet_UsersInRoles表的全表视图。

    vw_aspnet_UsersInRoles


    7.aspnet_Paths表的全表视图。

    vw_aspnet_WebPartState_Paths


    8.返回aspnet_PersonalizationAllUsers表的页面路径ID、以二进制形式保存的页面配置属性的长度和上次修改时间。

    vw_aspnet_WebPartState_Shared


    9.返回aspnet_WebPartState_User表的页面路径ID、用户ID、以二进制形式保存的页面配置属性的长度和上次修改时间。

    vw_aspnet_WebPartState_User