2006年12月16日所有随笔

使用 Profile 时登录和注销的情况

    当用户有设定配置属性值的时候,Profile 就会向数据源中各数据表添加记录。若用户是第一次设置自定义属性的,会向 aspnet_Applications 表添加一些新记录,从名字就可以看出它是记录应用程序相关信息的,然后再向 aspnet_Users 表添加一条记录,从名字也可以看出它是记录用户信息的,然后再向 aspnet_Profile 表添加一条记录,用户的配置的属性值就存在在这表里面,普通类型(System.String)的值会存储在 PropertyValuesString 字段里,默认是以 XML 序列化格式存储的,复杂的用户自定义类型经二进制序列化后存储在 PropertyValuesBinary 字段里。当然,在定义自定义类型时就要指定其是可序列化的。这样一来,当用户在设定了自己的配置属性值后,就会操作以上三个表(或二个表)。

    在默认情况下,当用户登录的时候,Profile 对象会读取与登录名相对应的 Profile 属性值,也就是说匿名用户的属性值与登录用户的属性值是不同的,同样说明在数据库表里是不同记录的,用户登录后,Profile 会在上面所说到的三个表中添加或检索与登录名对应的属性值。当用户关闭浏览器,在下一次打开网页时就会以匿名用户去搜索属性值,若用户在此之前删除过 IE 浏览器的 Cookies,那么此时登录网页将会以没有设定用户配置属性的状态显示,为什么会这样呢,因为一开始在有启用 Profile 功能的网站中,用户 Profile 是与一个随机生成的号码相关联的,该号码是根据每个用户唯一生成的,它保存在浏览器的 Cookies 中,当你清除了 Cookies,Profile 就会重新生成一个新的号码,并保存在 IE 的 Cookies 里,遗憾的是,aspnet_Users 表和 aspnet_Profile 表不会删除之前的记录。

  那有没有办法在登录后把匿名用户的配置属性值迁移到登录用户去呢?答案是肯定的。可以利用 ProfileModule 类的 MigrateAnonymous事件完成该任务,该事件只能在 Global.asax 文件中进行处理。如:

    // Global.asax

    void Profile_MigrateAnonymous(Object s, ProfileMigrateEventArgs e)
    {
        ProfileCommon anonProfile = Profile.GetProfile(e.AnonymousID);
        Profile.FavoriteColor = anonProfile.FavoriteColor;

        // Clean up anonymous profile
        ProfileManager.DeleteProfile(e.AnonymousID);
        AnonymousIdentificationModule.ClearAnonymousIdentifier();

        // Save profile
        Profile.Save();
    }

    该示例演示在用户登录后将匿名用户的配置属性 FavoriteColor 的值赋给已登录用户的 FavoriteColor 配置属性。若在登录后有修改过 FavoriteColor 属性,在下在次登录时还会被匿名的属性值复盖。在用户注销后,由于原来的匿名用户配置已被清除,所以将处于没设定配置属性的状态,然后用户再修改配置属性,又会向 aspnet_Users 表和 aspnet_Profile 表各添加一条新记录了!

    还有一点就是,虽然匿名用户的配置属性被消除,但在 aspnet_Users 表的记录却没被删除,而只是删除了 aspnet_Profile 表的。

    最后,可以通过 ProfileManager 类来管理这些 Profile 或生成信息报表,如果你愿意也可以手工删除表里的记录,但要有个顺序:aspnet_Profile -> aspnet_Users -> aspnet_Applications。

使用 Profile 对象存储用户配置信息

    ASP.NET 中的 Profile 对象与 Cookie 很相似,都是用于存储持久型信息,但比 Profile 提供更多的功能。

    现在很多网站都提供个性化外观,也就是提供让用户自己定义网页的外观,哪每个用户的配置信息保存在哪呢?Profile 对象就是负责这方面的。默认的情况下,Profile 将这些信息保存在数据库中。在使用的时候只要调用当前 HttpContext 的 Profile 属性即可,Profile 属性是一个 ProfileBase 类实例,ASP.NET 使用 ProfileBase 类创建用于用户配置文件的类。在启动启用了用户配置文件的应用程序时,ASP.NET 会创建一个类型为 ProfileCommon 的新类,该类从 ProfileBase 类继承,所有用户配置属性就存储在这个类里面,同时该也被加载到 HttpContext 的 Profile 属性里。一般地,要实现 Profile 功能,需要二个条件,一是配置 web.config 文件,二是配置数据库。

    配置 web.config 文件

    网站设计者可以根据需要定义可以让用户自定义的属性,如:网页底色、字体大小等等,如:

    <connectionStrings>
      <add name="SqlServices" connectionString="server=(local);uid=sa;pwd=;database=TestProfile" />
    </connectionStrings>

    <profile defaultProvider="SqlProvider">
      <providers>
          <add name="SqlProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="SqlServices" applicationName="TestProfile" description="SqlProfileProvider for TestProfile" />
      </providers>
      <properties>
          <add name="FavoriteColor" allowAnonymous="true" defaultValue="Red" />
          <add name="FontSize" allowAnonymous="true" defaultValue="12px" />
      </properties>
    </profile>

    以上配置信息定义了两个配置属性,一个是 FavoriteColor,默认值为:Red,一个是 FontSize,默认值为:12px。

    配置数据库

    要使数据库支持 Profile 功能,需要向数据库添加一些表和存储过程,当然啦,肯定不用我们自己去定义,使用 aspnet_regsql 工具自动为数据库添加 Profile 的功能支持。该工具位于 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ 里,可以在命令行窗口下输入 aspnet_regsql,然后回车,用向导的方式配置数据库,配置过程很简单,只要选中要配置的数据库,然后一路 Next 就行了,完了看一看数据库,增加了很多表、存储过程和视图,都是以 aspnet_ 开头命名的,有 11 表,55个存储过程,9 个视图,当然啦,这么多东西不是仅仅为了支持 Profile 功能,还有其它功能同样用到这个东西,如:Membership、MemberRoles,这几个功能都是采用 Provider 模式设计的。

    只要配置好以上两项工作,就可以用 Profile 功能了,如:

    // Test.aspx

    <body bgcolor="<%= Profile.FavoriteColor %>">


    以上所存储的 Red、12px 数据都是简单类型(System.String,也是默认的类型),也可以存储自定义的复杂类型(类类型)。

让用户控件实现缓存依赖

用户控件的输出缓存的设置的编程访问主要通过 CachePolicy 属性,该属性获取对该用户控件的缓存参数集合的引用,该参数集合封装为一个 ControlCachePolicy 类。该类提供对 ASP.NET 用户控件的输出缓存的设置的编程访问。要使用 CachePolicy 属性,用户控件必需启用输出缓存,常用启用输出缓存的方法有两种,一是在用户控件中使用 @ OutputCache 指令来启用输出缓存,如:

<%@ OutputCache Duration="100" VaryByParam="none" %>

二是将用户控件嵌入在 PartialCachingControl 实例中,如:

PartialCachingControl pcc = LoadControl("SimpleControl.ascx") as PartialCachingControl;
Controls.Add(pcc);

下面主要说说利用 ControlCachePolicy.Dependency 属性来控制缓存数据过期的问题。

假如一个页面的内容是从数据库读出的,页面在缓存的时间为 100 秒,若数据库表在 100 秒发生的变将不会立即反应到页面上的,100 秒刷新到的数据都是旧的数据,而不是数据库最新的数据,这在一般的应用没有多大的影响,但在一些要求数据比较实时的情况下,是不允许的。然而我们可以通过输出缓存类 ControlCachePolicy 的 Dependency 属性,设置一个缓存依赖项,来监视数据库表的变化,从而使数据表的变化和缓存中的数据达到一致。Dependency 属性是一个 CacheDependency 类实例,CacheDependency 类监视依附性关系,以便在任何这些对象(依赖项)更改时,该缓存项都会自动移除。(未完待续……)