2006年12月所有随笔

使用 Forms 身份验证的一点点心得

如果采用 Forms 验证,当用户通过验证后 Context.User.Identity 或 Page.User.Identity 是一个 System.Security.Principal.IIdentity


System.Security.Principal 命名空间定义表示代码在其中运行的安全上下文的用户对象。

未验证:

Context.User: System.Security.Principal.GenericPrincipal,实现 System.Security.Principal.IPrincipal 接口,表示一般用户
Context.User.Identity: System.Security.Principal.GenericIdentity,实现 System.Security.Principal.IIdentity 接口,表示一般用户

Forms 验证后:

Context.User: 同与未验证
Context.User.Identity: System.Web.Security.FormsIdentity,实现 System.Security.Principal.IIdentity 接口,表示一个使用 Forms 身份验证进行了身份验证的用户标识。


可以根据需要创建自己的用户对象(Principal),需要实现 System.Security.Principal.IPrincipal 接口。


验证后,可以用 FormsAuthentication.SetAuthCookie("UserName", true); 给以 UserName 为用户创建一个票据,事实上是创建一个 Cookies,创建之后,用户在访问那些需要通过用户验证才能访问的页时就不用每次提供票据了(也就是不用每次都输入用户名和密码去登录)。此 Cookies 的过期时间在 web.config 里设置如:

    <authentication mode="Forms">
      <forms name="GLUserAuth" loginUrl="Login.aspx" timeout="10" />
    </authentication>

如以上设置,若用户在 10 分钟内未对应用程序进行任何操作,此票据(cookies)将自动失效。

怎样设置哪些页需要用户通过身份验证后才能访问,用 <location> 配置节:

  <location path="EditUser.aspx">
    <system.web>
      <authorization>
        <deny users="?" />
      </authorization>
    </system.web>
  </location>

当然啦,如果所有页都需要就不是这样设置的了。最后可以用:FormsAuthentication.SignOut() 方法从浏览器删除 Forms 身份验证票证。

Asp.net 中 Password 型 TextBox 在服务器赋值[转]

出于安全性考虑,Asp.net 中 Password 型 TextBox 不允许从服务器赋值;

解决方法:this.txtPassword.Attributes.Add("value",Request.Cookies["pwd"].Value);

地震了,吓了一跳!

  昨晚 20:26 和 20:34 分别发生了两次地震,震中位于台湾南部海域,汕头有震感,部分地区震感稍强,我那可能就属于“稍强”地区吧,我家住七楼,能不强吗?当时我正在书房专心研究 .Net,突然书架的玻璃前后摇动,响得很,还以为是自己身体抖动所致,站起来一看,还在摇,这时突然听见我老婆喊了一声:“哎,地震了!”,我马上跑过去,立式的空调还在动,两人走到阳台,第一次地震已过了。过了一会,老婆打个电话给老妈报个平安,我继续回书房,刚坐下不久,又来了,马上跑了出来,见老婆还在打电话,我说:“快点出去好了”,她挂电话后还拿钥匙,然后跟我说往天台跑,门还是她锁的。此事可见老婆比我还镇定,我两次跑都跑在她前面,唉!愧为男子汉啊!

Web Application Project 模式下的 ProfileCommon 类的问题

  假如我们在 ASP.NET 程序中使用了用户配置文件(Profile),也就是应用程序配置文件(web.config)中包含了配置文件的属性(<profile>节)的定义,那么 ASP.NET 会自动生成一个名为 ProfileCommon 的类,继承于 System.Web.Profile.ProfileBase 类,MSDN 有如下说明:

    ASP.NET 使用 ProfileBase 类创建用于用户配置文件的类。在启动启用了用户配置文件的应用程序时,ASP.NET 会创建一个类型为 ProfileCommon 的新类,该类从 ProfileBase 类继承。强类型访问器被添加到 profile 配置节中为每个属性定义的 ProfileCommon 类中。

  我们在类视图可以看到 ProfileCommon 类的定义,打开一看,看路径,它不放在我们自己程序的目录下,而是放在 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 目录下的某个目录(和你的项目名称同名)里,Temporary ASP.NET Files 目录是 asp.net 在编译和调试时的临时目录,一般是放那些 ASP.NET 自动生成的代码或 DLL 文件,像上面所说的 ProfileCommon 类文件就放在里面。

  当程序运行时,ProfileCommon 类的一个实例被设置为 ASP.NET 应用程序的 Profile 属性的值。也就是 HttpContext.Profile 属性的值,并为每一个 .aspx 页和 .ascx 页添加了一个 Profile 属性,我们在 Temporary ASP.NET Files 目录下就可在相应页的 .cs 文件找到这些代码:

    // WebUserControl.ascx
    public partial class WebUserControl {
        protected ProfileCommon Profile {
            get {
                return ((ProfileCommon)(this.Context.Profile));
            }
        }

        protected System.Web.HttpApplication ApplicationInstance {
            get {
                return ((System.Web.HttpApplication)(this.Context.ApplicationInstance));
            }
        }
    }

  然后,我们就可以在页上用 Profile 属性来访问用户的配置文件属性的值了:

    protected void Page_Load(object sender, EventArgs e)
    {
        Profile.CartInfo = "Good";

        string user = Profile.UserInfo;
    }

    要注意的是,以上所说的情况只适应于 Web Site 模式,在 Web Application Project 模式里是不支持的。


    Web Application Project 模式也自动生成 ProfileCommon 类(可从 Temporary ASP.NET Files 目录下找到),但是以 Web Site 模式生成,在类视图也不到,也没自动为每一个 .aspx 页和 .ascx 页添加了 Profile 属性,这么一来显示是没法通过页的 Profile 属性去访问配置文件的属性值,通过手工方式把 Temporary ASP.NET Files 目录里的 ProfileCommon 类的代码加到自己的程序里,也同样无法解决这个问题。Visual Studio 2005 SP1 在12月14日已经发布,SP1 已包经含了 Web Application Project!但不知有没把这个特性加上去(今天弄了一天还没把 SP1 装,也有人说 VS 2005 SP1 是 MS 最差劲的补丁程序,安装时间比原版的要长,空间占的多!)。

    还是说说上面所说的问题吧。ASP.NET 没自动生成就得靠自己手工生成了,可以到:

    http://www.gotdotnet.com/workspaces/workspace.aspx?id=406eefba-2dd9-4d80-a48c-b4f135df4127

    下载一个 ASP.Net WebProfile Generator,它是个 VS IDE 外接程序,它会根据你的 Web.config 文件里的<profile>配置节的配置,自动生成类似于 ProfileCommon 类的一个类 WebProfile(具体如何操作看里面的 readme.txt)。生成后最好不要手工去改动这个类,当你的配置文件有改动<profile>节时,只要重新生成一次就行了,更不要把类名改为 ProfileCommon,因为 ASP.Net 一见到有 ProfileCommon 就高兴,就会自动给每个 .aspx 页和 .ascx 页添加一个 Profile 属性,但又没去理会 WebProfile Generator 的意思,最终导致运行时还是有错误。

    自动生成 WebProfile 后,还要在需要读取到配置文件属性的页添加一个属性,以便操作用户配置文件属性:

    public partial class WishList : System.Web.UI.Page
    {
        // 手动添加此属性 **************
        private WebProfile Profile
        {
            get { return new WebProfile(Context.Profile); }
        }
        // **************

        protected void Page_Load(object sender, EventArgs e)
        {
            Profile.UserInfo = "pcvc.net";
        }
    }

    也可以这样:

    string s = WebProfile.Current.MyProperty;
    WebProfile.Current.MyGroup.MyProperty = "value";


    注意,ASP.Net WebProfile Generator 只能用于 Visual Studio 2005 英文版的 Web Application Project 模式下。

Visual Studio 2005 Service Pack 1 (SP1) Released

Visual Studio 2005 SP1 已于2006年12月14日发布了!可到以下地址下载:

http://msdn.microsoft.com/vstudio/support/vs2005sp1/default.aspx

安装程序有 400 多M,要注意的是在 windows xp 或 windows 2003 安装可能会发生:

安装大 WindowsInstaller 包或大型 WindowsInstaller 修补程序包时错误信息: " Error 1718。 文件被数字签名策略拒绝 "


要解决此问题, 请按照下列步骤:

1. 打开 控制面板 的 管理工具。
2. 双击 本地安全策略 。
3. 单击 软件限制策略 。

注意 如果列出, 没有软件限制右键单击 软件限制策略 , 然后单击 新建策略
4. 在 对象类型 , 双击 强制 。
5. 单击 除本地管理员以外的所有用户 , 并单击 确定 。
6. 重新启动计算机。

for more infomation: http://support.microsoft.com/kb/925336

参考:
http://weblogs.asp.net/scottgu/archive/2006/12/15/visual-studio-2005-service-pack-1-sp1-released.aspx

使用 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 类监视依附性关系,以便在任何这些对象(依赖项)更改时,该缓存项都会自动移除。(未完待续……)

C#学习(一)

1. as 关键字其实是将类型进行内置转换,且只能用于引用类型

string xml = command.ExecuteScalar() as string;

注意:string 是 .NET Framework 中的 String 的别名,是内置 C# 类型,不是值类型。


2. 各值类型的 Parse 方法,只是将其值的字符串表示形式转换为它的等效的值

int n = int.Parse("123");


3. 各值类型的默认值

值类型的默认值是由默认构造函数返回的值类型的默认值。默认构造函数是通过 new 运算符来调用的,如下所示:

int myInt = new int();

以上语句同下列语句效果相同:

int myInt = 0;

请记住:在 C# 中不允许使用未初始化的变量。

int myInt;
Console.Write(myInt);

以上语句将报错。


值类型    默认值 
------------------
bool      false
byte      0
char      '\0'
decimal   0.0M
double    0.0D
enum      表达式 (E)0 产生的值,其中 E 为 enum 标识符。
float     0.0F
int       0
long      0L
sbyte     0
short     0
struct    将所有的值类型字段设置为默认值并将所有的引用类型字段设置为 null 时产生的值。
uint      0
ulong     0
ushort    0


4. 下表按类别列出了 C# 的值类型

值类型    类别
------------------
bool      布尔型
byte      无符号、数值、整数
char      无符号、数值、整数
decimal   数值、十进制
double    数值、浮点
enum      枚举
float     数值、浮点
int       有符号、数值、整数
long      有符号、数值、整数
sbyte     有符号、数值、整数
short     有符号、数值、整数
struct    用户定义的结构
uint      无符号、数值、整数
ulong     无符号、数值、整数
ushort    无符号、数值、整数

好久没写东西了

  好久没写东西了,自上个星期五起,都在玩 Ubuntu (一个 Linux 的发行版),从 Desktop CD 版到 Server 版,一路都很顺,我是在 VMware 装的,这样就方便多了,之所以玩这东西,是近来在学 Pthon,Django,Postgresql,这些东西一般在 Linux 下跑会比较好点,在 windows 下有点不方便,但也可以跑。

  Python 确实是个比较有趣有语言,Django 是基于 Python 的一个 Web Framework,专门用于开发 Web 程序,代码量很少,Postgresql 是数据库,听牛人说是最强、最复杂的数据库系统,有些特性和功能连一些商业产品也没具备。以上这些东西都是免费的,且开源的。近来接触的东西都是开源的,做人做事也要有开源的思想,心胸要扩,只有开源和交流自己才能有进步,太封闭,自已为是,是没什么多大长进的。

  在此建议 MS 的 Fans 们,多学 MS 以外的东西。