第四篇 应用程序 第一章 什么是应用程序 在asp.net中,可以这样来定义一个Application:能够在一个web应用服务器的子目录或者虚拟目录上运行的所有的文件、页面、操作、模块或者能被执行的代码。比方说,在一个web服务器上,一个“order“应用程序将会在“/order“这个目录下被发布。 Web服务器上的asp.net应用程序在一个被称作应用程序域运行空间(AppDomain)环境中被执行,以保证类的隔离(没有版本、名称上的冲突)、安全屏蔽(防止有权访问某些机器/网络的资源)、静态变量的隔离。 在一个web应用程序的生命周期中,asp.net维护一个HttpApplication实例池。Asp.net对一个Http的请求会自动分配一个来处理,这个特别的HttpApplication实例对管理这个在全部的生命周期里的请求是可靠的,并且在处理完成后可以被重用。 在应用程序环境下,ASP.NET并发处理客户端的请求,所以可能存在多线程对Application对象的同时存取。在这种情况下,对Application对象的草率处理,可能会导致不可预知的错误。例如以下代码: <% Application("counter") = CType(Application("counter") + 1, Int32) %> 原本希望对实例进行计数,但如果同时到达两个以上请求时,则有可能产生漏计。正确的方法应该是在操作以前,对Application对象上锁,操作完成以后,再对Application对象解锁。代码如下: <% Application.Lock() Application("counter") = CType(Application("counter") + 1, Int32) Application.UnLock() %> 4.1.1 配置应用程序的步骤 4.1.1.1 设置应用程序的目录结构 一个WEB站点可以有多个应用程序运行,而每一个应用程序可以用唯一的URL来访问,所以首先应利用IIS开放应用程序的目录为“虚拟目录”。各个应用程序的“虚拟目录”可以不存在任何物理上的关系。例如: 应用URL: 物理路径: http://www.my.com c:\inetpub\wwwroot http://www.my.com/myapp c:\myapp http://www.my.com/myapp/myapp1 \\computer2\test\myapp 从“虚拟目录”上看来,http://www.my.com/myapp和http://www.my.com/myapp/myapp1是乎存在某种联系,但实际情况却是,我们看到两者完全分布于不同的机器上,更不用说物理目录了。 4.1.1.2.设置相应的配置文件 根据应用的具体需要,可以拷入相应的global.asax和config.web配置文件,并且设置相应的选项。(配置文件的设置具体见相关章节) global.asax主要配置application_start、applicatoin_end、session_start、session_end等事件。 4.1.1. 3.把应用所涉及的各种文件放入“虚拟目录“中 把.aspx文件、.ascx文件以及各种资源文件分门别类放入应用目录中,把类引用所涉及的集合放入应用目录下的bin目录中。 4.1.2 应用程序框架 <%@ Application attribute="value" [attribute=value … ]%> <%@ Import namespace="value" %>… <%@ Assembly Name="assemblyname" %> <script language=”vb” runsat=server> … </script> <body> <form runat=server> … </form> </body> </html> 说明: 1.<%@ Application attribute="value" [attribute=value … ]%> 让ASP.NET运行环境动态从另一个应用中动态编译出一个类来继承使用。 例如: <%@ Application Inherits="MyApp.Object" Description="Ourapp" %> 指定应用环境从Myapp应用中动态编译一个MyApp.Object的类以供使用,它的说明为“Ourapp”。 2.<%@ Import namespace="value" %>… 显视导入一个命名空间到应用程序,这样应用程序就可以使用命名空间中定义的各种类和接口来完成特定的功能,大大加快了程序的开发速度。 例如: <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.NET” %> 就可以利用系统为我们提供的大量文件和网络对象,快速的开发自己的文件和网络应用程序。 3.<%@ Assembly Name="assemblyname" %> 在页面编译时产生到assemblyname的连接,这样就可以使用集合中类及接口。缺省情况下,应用会把应用程序目录下bin中的集合都动态载入。该项功能也可以在应用程序的config.web中配置,缺省情况下,config.web中有如下形式: <assembly> <add assembly="*"/> </assembly> 即缺省情况下,加载bin下的所有集合。 又如: <%@ Assembly Name="myassembly.dll" %> 加载bin下myassembly.dll集合 4.其他 <script>、</script>对之间的代码通常是各种事件的定义,诸如页面开始时、某个按件被触发时所要做的事情。<body>、</body>和<form>、</form>之间通常是页面的界面要素,为显示给客户端的可视界面。 4.1.3 创建应用程序的典型步骤 4.1.3.1 配置config.web 主要定义为gb2312字符集,以利于中文显示 <configuration> <globalization requestencoding="gb2312" responseencoding="gb2312" /> </configuration> 4.1.3.2 配置global.asax 主要定义应用初始化、结束,会话开始、结束,请求开始、结束等事件发生时,应用要做的事情。 <script language="VB" runat="server"> Sub Application_Start(Sender As Object, E As EventArgs) End Sub Sub Application_End(Sender As Object, E As EventArgs) End Sub Sub Session_Start(Sender As Object, E As EventArgs) End Sub Sub Session_End(Sender As Object, E As EventArgs) End Sub Sub Application_BeginRequest(Sender As Object, E As EventArgs) End Sub Sub Application_EndRequest(Sender As Object, E As EventArgs) End Sub </script> 4.1.3.3 主程序 创建一个应用程序我们可以先在web服务器上创建一个虚拟目录或者在发布目录下创建一个新的目录。装过Windows 2000 Advance Server的读者会知道,安装完成后,会有一个c:/inetpub/wwwroot的目录,你可以通过IIS管理工具来创建一个新的目录或者虚拟目录。一个应用程序可能含有大量的.aspx文件、.ascx文件、由其他工具产生的assembly集合以及页面中用到的各种资源文件(声音、图片、动画等等),这里就不再一一介绍了。 下面我们就创建一个简单的aspx页面来说明一个Application的应用,它只含有一个.aspx文件,在用户浏览时显示“hello world”,可谓最简单的web应用了。 <!-- 文件名:application/FormAppHellp.aspx --> <%@Page Language="VB"%> <html> <head> <title> hello world </title> </head> <body> <center> <h1><% Response.Write("Hello World!") %></h1> </center> </body> </html> 下面就是我们的运行效果:  4.1.4 小结 asp.net平台的应用,通过指定虚拟目录,使得一个主机多个地址多个应用成为可能。采用asp.net开发应用程序带来的好处是:程序集中可方便打包,配置的层次结构更加灵活方便,应用独立运行于自身的应用环境中更加安全可靠。 配置一个应用的过程大致为:1)指定应用目录为IIS的虚拟目录2)为应用设置适当的配置权限(配置global.asax和config.web文件)3)在自己的应用目录下放置事先编好的程序。 从页面应用所支持的Application、Import、Assemly等标识看来,asp.net对对象重用的支持大大加强了,ASP.NET的“通用语言运行库”概念的提出,为实现各种开发语言的合作编程奠定了基础。 第二章 配置Config.web 4.2.1 ASP.NET配置简介 ASP.NET提供了一个丰富而可行的配置系统,以帮助管理人员轻松快速的建立自己的WEB应用环境。ASP.NET提供的是一个层次配置架构,可以帮助WEB应用、站点、机器分别配置自己的扩展配置数据。ASP.NET的配置系统具有以下优点: ASP.NET允许配置内容可以和静态内容、动态页面和商业对象放置在同一应用的目录结构下。当管理人员需要安装新的ASP.NET应用时,只需要将应用目录拷贝到新的机器上即可。 ASP.NET的配置内容以纯文本方式保存,可以以任意标准的文本编辑器、XML解析器和脚本语言解释、修改配置内容。 ASP.NET 提供了扩展配置内容的架构,以支持第三方开发者配置自己的内容。 ASP.NET配置文件的更修被系统自动监控,无须管理人员手工干预。 4.2.2 配置文件的规则 ASP.NET的配置文件是基于XML格式的纯文本文件,存在于应用的各个目录下,统一命名为“config.web”。它决定了所在目录及其子目录的配置信息,并且子目录下的配置信息覆盖其父目录的配置。 WINNT\Microsoft.NET\Framework\版本号\下的config.web为整个机器的根配置文件,它定义了整个环境下的缺省配置。 缺省情况下,浏览器是不能够直接访问目录下的config.web文件。 在运行状态下,ASP.NET会根据远程URL请求,把访问路径下的各个config.web配置文件叠加,产生一个唯一的配置集合。举例来说,一个对URL: http://localhost\webapp\owndir\ test.aspx的访问,ASP.NET会根据以下顺序来决定最终的配置情况: 1..\Microsoft.NET\Framework\v.1.00\config.web (缺省配置文件) 2..\webapp\config.web (应用的配置) 3..\webapp\owndir\config.web (自己的配置) 4.2.3 配置文件的语法规则 标识 配置内容被置于config.web文件中的标记<configuration>和</configuration>之间。 格式: <configuration> 配置内容 … </configuration> 2)配置段句柄说明 ASP.NET的配置文件架构并未指定任何文件格式或者是支持的配置属性。相反的,它提出了“配置段句柄申明”的概念来支持任意的用户定义配置段。 格式: <configsections> <add name=欲定义配置段名 type=处理的句柄函数 /> </configsections> 配置段 具体定义配置的内容,供应用使用。 以下例子定义了一个“httpmodules”配置段,设置了系统http相关的处理模块 <configuration> <configsections> <add name="httpmodules" type="System.Web.Configuration.HttpModules ConfigurationHandler" /> </configsections> <httpmodules> <add type="System.Web.SessionState.CookielessSessionModule" /> <add type="System.Web.Caching.OutputCacheModule" /> <add type="System.Web.SessionState.SessionStateModule" /> <add type="System.Web.Security.WindowsAuthenticationModule" /> <add type="System.Web.Security.CookieAuthenticationModule" /> <add type="System.Web.Security.PassportAuthenticationModule" /> <add type="System.Web.Security.CustomAuthenticationModule" /> <add type="System.Web.Security.UrlAuthorizationModule" /> <add type="System.Web.Security.FileAuthorizationModule" /> </httpmodules> </configuration> 4.2. 4 ASP.NET定义的标准配置段 httpmodule 段: 定义了应用的http请求的处理模块以及诸如安全、日志之类的应用方式 httphandlers 段: 负责映射URLs到IhttpHandler类 sessionstat 段: 负责配置http模块的会话状态 globalization 段: 配置应用的公用设置 compilation 段: 配置ASP.NET的编译环境 trace    段: 配置ASP.NET的跟踪服务 security 段: ASP.NET的安全配置 iisprocessmodel 段: 在IIS上配置ASP.NET的处理模式 browercaps 段: 配置浏览器的兼容部件 4.2. 5 一个配置读出的例子 config.web配置文件 <!--config.web 请放入FormCfg.aspx所在目录--> <configuration> <!--申明一个test配置段--> <configsections> <add name="test" type="System.Web.Configuration.DictionarySectionHandler" /> </configsections> <test> <!--配置一个键key,其内容为just a configure test--> <add key="key" value="just a configure test" /> </test> </configuration> 读出其内容 <!--文件名:Application/FormCfg.aspx--> <html> <head> <script language="VB" runat=server> sub page_load(s as object ,e as eventargs) '取出test配置段的key键的值 Dim CfgSection As Hashtable = Context.GetConfig("test") Dim Msg As String = CStr(CfgSection("key")) lblMsg.text=Msg end sub </script> <title> 配置信息的读取 </title> </head> <body> <center> config.web中"test"配置段中key的内容为: <asp:label id=lblmsg runat=server /> </center> </body> </html> 运行结果  4.2. 6 Config.web配置实例 <configuration> <!--定义用户应用的公用设置,如SQL的sql连接串等等--> <appsettings> </appsettings> <!--设置浏览器的兼容性部件--> <browsercaps> </browsercaps> <!--编译环境设置,非调试模式--> <compilation debugmode="false"> <!--缺省编译语言为vb,以后可以不再在Page中定义脚本语言--> <compilers defaultlanguage="vb"> <!--以MSVSA.dll编译.vb为后缀的VB文件--> <compiler language="VB" extension=".vb" type="MSVSA.dll#Microsoft.VB.Compiler"/> </compilers> <assemblies> <!--加入对System.Data的引用--> <add assembly="System.Data" /> <!--去掉对System.Data的引用--> <remove assembly="System.IO" /> <!--去掉config.web中包含或继承来的引用--> <clear /> </assemblies> </compilation> <!--设置应用全局环境--> <!--文件、请求、返回以gb2312编码,以保证浏览器正确显示中文--> <globalization fileencoding="gb2312" requestencoding="gb2312" responseencoding="gb2312"/> <!--定义用户出错的处理--> <!--出错缺省显示defaultredirect指定的页面,mode为on时,遵循customerrors配置段--> <!--mode为off时,忽略用户出错,mode为remoteonly时,本地才显示真正的出错原因--> <customerrors defaultredirect="AnErrorHasOccured.aspx?ErrNum=-1" mode="remote"> <!--当出错码为500时,显示redirect指定的页面--> <error statuscode="500" redirect="AnErrorHasOccured.aspx?ErrNum=500"/> </customerrors> <!--指定目录webapp的访问权限--> <location path="webapp” > <!--非授权用户不能进入webapp目录--> <security> <authorization> <deny users="?" /> </authorization> </security> </location> <!--定义安全属性--> <security> <authorization> <!--角色为Adminstrators和所有的用户访问其指定的资源--> <allow roles="Adminstrators"/> <allow users="*" /> </authorization> </security> </configuration> 4.2.7 小结 Config.web是aspx区别于asp的一个方面,我们可以用这个文件配置我们的很多信息。 第三章 编写global.asax 为了编写用户界面的应用程序,开发者可以把应用程序标准的逻辑和时间处理的代码加到Web Application 里面。这些代码不产生用户界面,也不想英单个得页面的请求。事实上,这些代码处理更高水平的事件,如Application_Start, Application_End, Session_Start, Session_End,等等。开发者通过放在web应用程序根目录下面的Global.asax来响应这些事件。 Asp.net通过一个动态的.NET FrameWork 类自动解析和编译这个文件,这个类就是HttpApplication基类,在第一时间里面,在这个文件里面的应用程序的资源将会被响应。 首先,在包含有请求的应用程序名字空间中被访问之前,Global.asax将被解析和编译成.NET Framework的一个类。这个文件本身有拒绝被访问的配置。 下面我们来看看这个文件里面的具体内容,首先我们声明这个文件的使用语言、运行环境: <script language=”VB” runat=server> ‘相关方法 </script> 然后我们就可以定义各种方法了, Sub Application_Start() ‘方法的属性等 End Sub 如果事件处理代码需要用到名字空间,我们可以这样来引用它: <%@ Import Namespace=”System.Data.SQL”%> 下面我们来看看这个文件的具体应用,首先我们在我们的Web Server上建立一个Global.asax文件,我们在里面加上我们的代码: <script language=”VB” runat=server> ‘相关方法 Sub Application_Start() ‘方法的属性等 End Sub Sub Application_Start(Sender As Object, E As EventArgs) Application.Lock() Application("counter") = CType(Application("counter") + 1, Int32) Application.UnLock() End Sub Sub Application_End(Sender As Object, E As EventArgs) ' Clean up application resources here End Sub Sub Session_Start(Sender As Object, E As EventArgs) Response.Write("Session 正在启动...<br>") End Sub Sub Session_End(Sender As Object, E As EventArgs) ' Clean up session resources here End Sub </script> 当然,我们还要配置Config.web,用来指定出错信息的打印页面。根据上面我们配置Config.web的经验,我们很容易的就可以对这个文件进行配置: <configuration> <customerrors mode="on" defaultredirect="error.htm" /> <globalization requestencoding="gb2312" responseencoding="gb2312" /> </configuration> 第二句话就是配置我们指定的出错页面语句。我们写两个页面来实现它,一个为出错页面,一个为实现这个功能的aspx页面。出错页面很简单的,就是报告程序出错时显示的信息,我们就写“在config.web里面配置的连接!“,是经过aspx页面甩出来的。 在aspx页面,我们用下面的语句来响应出错按钮点击事件: Sub Error_Click(Sender As Object, E As EventArgs) ‘甩出异常! throw New Exception() End Sub 以外我们的响应Session的方法用下面的语句来说明: Sub Session_Click(Sender As Object, E As EventArgs) Session.Abandon() Response.Redirect("global.aspx") End Sub 下面是完整的代码: <html> <script language="VB" runat="server"> '页面导入 Sub Page_Load(Sender As Object, E As EventArgs) Response.Write("正在装入页面...<br>") End Sub 'Session事件 Sub ssaidy(Sender As Object, E As EventArgs) Session.Abandon() Response.Redirect("global.aspx") End Sub '响应错误方法 Sub esaidy(Sender As Object, E As EventArgs) '抛出异常 throw New Exception() End Sub </script> <body> <br><br><br> <center> <form runat="server"> <input type="submit" Value="刷新这个页面" runat="server"/> <input type="submit" OnServerClick="ssaidy" Value="结束这个Session" runat="server"/> <input type="submit" OnServerClick="esaidy" Value="错误表示" runat="server"/><p> <hr> </form> </center> <br><br> </body> </html> 运行结果如下:  点击“错误表示“按钮,显示如下:  4.3.1小结 讲述了配置文件Global.asax的配置问题,Global.asax文件对一个.NET技术构建的WEB站点来讲,是非常必须的,本章我们的内容就是针对它讲的。 第四章 Application和Session 4.4.1 Application对象 在讲述ASP.NET的Application对象之前,我们先来回顾一下ASP的Application对象。我们知道由于变量的生命周期受限于网页,所以每当.asp文件被解释执行完毕之后时,变量就会被释放,它的内容将不存在。而在编程过程中,我们有时又需要在页面之间传递变量的内容。例如,我们在一个登录页面中输入了用户的名字,为了使页面个性化,在后面的页面显示中,我们希望知道前面输入的用户名,以便于更好的人机交互。这就要求有一种变量传递的机制。人们最常用的保存变量的内容的方法是使用文件,但是毕竟对文件的的操作是比较麻烦的事情,有没有更简单的方法呢?其中一种比较简单的方法就是使用Application对象来保存我们希望传递的变量。由于在整个应用程序生存周期中,Application对象都是有效的,所以在不同的页面中都可以对它进行存取,就像使用全局变量一样方便。在asp.net环境下,Application对象来自HttpApplictionStat类。它可以在多个请求、连接之间共享公用信息,也可以在各个请求连接之间充当信息传递的管道。 4.4.1.1 使用Application对象 Application对象重要的属性: ·All属性,返回应用中保存的所有的公用对象数组 例如: dim MyObjects() as object MyObjects=Application.All 表示用myobjects取得了当前应用保存的所有对象 ·AllKeys属性,返回应用中保存的公用对象的名字数组(标识数组) 例如: dim MyVars() as String MyVars=Application.AllKeys 即取得了所有保存的公用对象的标识名字到myvars数组 ·Contents属性,返回this指针,主要是为了和asp兼容而保留 ·Count属性,返回当前应用中保存的公用对象的数目 例如: dim VarNum as integer VarNum=Appliction.count ·Item属性,返回当前应用中保存的公用对象集合中的指定对象,这是最常用的属性。 例如我们前面讨论的,记录变量内容的问题,就是通过item属性来保存的。 Appliction.Item(变量名)=要保存对象 但是通常我们都会省去item属性写成: Application(变量名)=要保存对象 这里需要注意的是,Application保存的对象为应用程序所共享,而.net平台又是一个多用户多线程的环境,因而Application保存的对象在使用时,要注意避免冲突。 例如: Application(”counter”)= Application(”counter”)+1 它使开始用户保存的数值加1,我们可以利用它来统计页面浏览的次数。但是有一个问题发生了,那就是如果另外一个页面也使用了上述语句,那么混乱就产生了。设想一下如下情况,用户a对页面a访问,使counter+1,然后用户b对页面b的访问,counter又增加了1,实际上无论对页面a还是页面b,访问都只有一次,counter却增加了2次,由于记数变量的相同使得我们统计页面的努力化为泡影。 ·StaticObjects属性,返回在应用程序文件中型如<object runat=server></object>定义的对象的集合。 下面,我们对上面学到的各种属性进行应用。 例子: 我们首先产生6个Application变量,然后分别用item属性和all属性去逐一取出各个Application变量的内容显示出来。注意为了避免其他公用Application变量的干扰,我们在页面加载时,调用了removeall方法,清空应用的所有公用变量。 程序源代码 <!-- 文件名:Application\FormAppliction.aspx --> <html> <script language="vb" runat=server> Sub Page_Load(o as object,e as eventargs) dim i as integer dim tStr as String dim sStr as String dim strArray() as String dim tObject() as Object dim ObCol as HttpStaticObjectsCollection If Not IsPostBack Application.removeall '为防止其他变量干扰,使用前清掉所有的保存变量 '保存六个变量 for i=1 to 6 tStr="变量名" & i sStr="内容" & i Application(tStr)=sStr next Else '采用item属性遍历 response.write("<center><b>采用item属性显示</b></center><br>") strArray=Application.Allkeys for i=1 to Application.count tStr= strArray(i-1) & "=" & Application.item(i-1)&"&nbsp;&nbsp;" response.write(tStr) next '采用All属性遍历 response.write("<hr><center><b>采用All属性显示</b></center><br>") tObject=Application.All for i=1 to Application.count tStr=tObject(i-1).ToString & "&nbsp;&nbsp;" response.write(tStr) next '显示有多少个object定义 ObCol=Application.StaticObjects response.write("<hr>含有object标识:" & ObCol.count & "个") End If End Sub </script> <head> <title> Appliction对象试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>Appliction对象试验</h2> <hr> <form runat=server> <asp:button text="显示Appliction内容" runat=server /> </form> </center> </body> </html> 2.开始时,页面的输出画面  3.当按下显示按钮后,显示appliction内容的画面:  Application对象重要的方法调用: ·Add方法,加入一个对象到Application对象的Stat集合中 例如: Application.Add(“string1”,”test”) 表示向Application的stat集合中加入一个名为string1的值为”test”的字符串,其实它的效果和 Application(“string1”)=”test” 以及Application.item(“string1”)=”test” 是一样的。 ·Remove方法,根据给出的标识从Application对象的Stat集合中删去 例如: Application.Remove(“string1”) 表示把标识为string1的共享对象string1从Application对象的Stat集合中删去。使用它可以清除用Add方法添加的对象。 ·RemoveAll方法,把Application对象Stat集合中的所有对象清除,在我们对属性的使用举例中,我们已经见过了它的用法,但是值得小心,我们不提倡使用它,因为在编程中你并不清楚,是否有其他页面要依赖于某个Application的公用变量,一旦清除将造成不可预知的错误。 ·Clear方法,作用和RemoveAll方法一样。 ·Get方法,允许使用名字标识或者是下标,来取得Application对象stat集合中的对象元素。 例如: dim tmp as object tmp=Application.Get(“string1”) 或者 tmp=Application.Get(0) 表示从Application对象的Stat集合中取得标识为string1或者下标为0的对象 它等价于: tmp=Application(“string1”) tmp=Application(0) 或者是 tmp=Application.item(“string1”) tmp=Application.item(0) ·Set方法,修改Application对象stat 集合中指定标识所对应的对象的值。 例如: Application.Set(“string1”,”try”) 就把我们开始为string1变量设置的值”test”改为”try”了,它和下边的形式也是一样的: Application(“string1”)=try ·GetKey方法,根据给定的下标取得Application对象的stat集合中相应对象的标识名。 例如: dim nameStr as String nameStr=Application.GetKey(0) 表示取得Application对象中Stat集合的第一个对象的标识名 ·Lock方法,锁住其他线程对Application对象中stat集合的访问权限。这个方法主要是用来防止对Application的变量操作过程中,其他并发程序可能造成的影响。比如在记数过程中,如果不进行上锁操作,就有可能发生脏读脏写。例如,开始从变量中取得记数值1, 如果在记数并写回到变量之间,另一页面对它发生了一次记数,并先行写回变量,那么最终写回到变量中的值为2,而并不是实际的3。如果采用了上锁机制,在页面读出变量到记数并写回变量的过程中,即使发生了另一次记数,由于变量被锁住,它也不可能在变量被写回以前取得成功,只有等待变量释放,从而形成两者对变量操作的串行性,避免了数据的脏读和脏写。 ·Unlock方法,对Application对象Stat集合锁定的解锁操作,释放资源以供其他页面使用。 下面我们就上边学到的方法做一个例子,为了强调lock方法和unlock方法,我们将单独举一个例子。例子是这样的,开始我们创建6个Application变量,赋以数值序号,页面有3个按钮,分别是加1,减1和清除。当点击“加1“按钮后,我们会看到变量的值都会增加1,当点击”减1“按钮后,变量值都减1,当按下清除后,变量都消失了。在清除功能中,我们为了同时演示remove和clear方法,采用最后三个用clear清除,其他的逐一用remove清除。 源程序 <!-- 文件名:Application\FormApplication01.aspx --> <html> <script language="vb" runat=server> Sub Page_Load(o as object,e as eventargs) dim i as integer If Not IsPostBack for i=1 to 6 application.add("item"&i,i) next End If response.clear for i=0 to application.count-1 response.write(application.GetKey(i) & "=" & application.Get(i) & "<br>") next End Sub Sub AddOne(s as object,e as eventargs) '变量值加1 dim i as integer dim j as integer dim t as string for i=0 to Application.count-1 j=Application.Get(i)+1 t=Application.GetKey(i) Application.Set(t,j) next Page_Load(s,e) '刷新画面 End Sub Sub SubOne(s as object,e as eventargs) '变量减1 dim i as integer dim j as integer dim t as string for i=0 to Application.count-1 j=Application.Get(i)-1 t=Application.GetKey(i) Application.Set(t,j) next Page_Load(s,e) '刷新画面 End Sub Sub Gone(s as object,e as eventargs) '清空所有变量 dim i as integer for i=0 to Application.count-3 Application.Remove(i) next '演示remove方法 Application.clear '演示clear方法 Page_Load(s,e) '刷新画面 End Sub </script> <head> <title> Application方法试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>Application方法试验</h2> <hr> <form runat=server> <asp:button type="submit" text="+1" OnClick="AddOne" runat=server /> <asp:button type="submit" text="-1" OnClick="SubOne" runat=server /> <asp:button type="submit" text="清空" OnClick="Gone" runat=server /> </form> </center> </body> </html> 2.开始时,输出画面:  3.当两次点击+1后,输出的变量值:  4.当点击”-1”后,变量的值为:  5.当点击清空后,输出的画面  接下来,我们看一个使用lock和unlock方法制作计数器的例子:Application对象对不同的连接者是共用的,因此适合制作计数器。 程序代码如下: <!-- 文件名:application\FormAppLock.aspx --> <html> <script language="vb" runat=server> sub Page_Load(o as object,e as eventargs) Application.Lock() Application("counter") = CType(Application("counter") + 1, Int32) Application.UnLock() end sub </script> <head> <title> Application对象方法试验 </title> </head> <body> <center> <h2>Application对象Lock方法试验</h2> <hr> 你是第<%=Application("counter")%>位访问者! </center> </html> 效果图:  关于计数器非同步更新的问题 假设有两个上网者同时启动网页(这种情况很常见),同时执行了上面的步骤,他们读出的值是相同的,但结果都是相同的。很明显,访问量少了一次。如何处理呢?我们在这里举一个例子,假设我们都在使用一个数据库管理系统,有可能访问者同时对一张表进行操作,如果一人在修改这张表的数据,而另一个人在读数据,很明显此时数据前后就不一致。通过我们需要对表进行锁定。那么,我们可以锁定对象,程序修改为: Application.lock Application("counter") = CType(Application("counter") + 1, Int32) Application.unlock 这样,当某一程序执行了Application.lock之后,其他应用程序就暂时不能使用Application对象,直到Application unlock。 4.4.1.2 Application的事件 当Application对象的生命周期开始时,Application_onstart 事件会被启动,当Application对象的生命周期结束时Application_onend事件会被启动。通常我们会在global.asax中定义 Application_onstart 事件。这和ASP程序相类似,有一点差别是Application_onstart 事件是在global.asa中定义。还有就是除了以前的四个事件又 增加了 两个事件Application_BeginRequest事件 和 Application_EndRequest事件。 在上一个例子中我们实现了用计数器来对页面进行统计,但是这样的程序有这样的一个问题,就是只能统计单个的页面,我们在asp+中可以很轻松的实现对整个站点页面的统计。为了达到这个目的,我们使用将使用Application_BeginRequest事件和 Application_EndRequest事件。这两个事件在站点的任意一个文件被请求的时候都会被激发,因此我们便利用这个事件实现对站点的访问统计。 我们首先来看看这个global.asax 文件 <script language="VB" runat="server"> Sub Application_End(Sender As Object, E As EventArgs) '我们捎带实现了 站点的当前在线人数 dim intOnlineNumber as integer intOnlineNumber=cInt(Application("ONLINENUMBER"))-1 Application("ONLINENUMBER")=intOnlineNumber End Sub Sub Session_Start(Sender As Object, E As EventArgs) Application.Lock intOnlineNumber=cInt(Application("ONLINENUMBER"))+1 Application("ONLINENUMBER")=intOnlineNumber+1 Application.UnLock End Sub Sub Application_BeginRequest(Sender As Object, E As EventArgs) response.write("当前访问的页面是 " + Request.FilePath + "<br>") '既然我们可以得到FilePAth 则我们只要把这个参数进行详细的各种各样的统计就可以了 End Sub </script> '好了一切完结之后,我们访问站点的任意一个aspx 文件,都会在最上方发现一行文字:当前访问的页面是 。。。。 怎么样,还不赶快尝试一下?? 4.4.2 Session 4.4.2.1 Asp.net里的Session 对Session的应用,我们通过在Global.asax中设置,然后在aspx页面中调用来进行。下面我们就一个例子来说明这个问题。 4.4.2.2 一个Session例子: 我们在Global.asax中加上一个Session_Start方法,在里面定义响应的属性: Sub Session_Start(Sender As Object, E As EventArgs) Session("name") = "saidy" Session("email") = "saidychan@sina.com" Session("tel") = "130000121553" End Sub 赋予属性一个初始值,这样当我们在调用页面(session.aspx)装入时直接就用这些默认值: <script language="VB" runat="server"> '返回Session值方法: Function getinfo(Key As String) As String Return Session(Key).ToString() End Function </script> 注意Key的定义,我们用这个语句获得方法的具体返回值,如“name“值: <%=getinfo("name")%> 在另外一个文件(info.aspx)中,我们用下面的语句来获得数据: Sub sc(Sender As Object, E As EventArgs) Session("name") = name.Value Session("email") = email.Value Session("tel") = tel.Value Response.Redirect(State("Referer").ToString()) End Sub 保存在Session中。 下面是我们具体的代码: application\Global.asax文件: <script language="VB" runat="server"> Sub Session_Start(Sender As Object, E As EventArgs) Session("name") = "global_saidy" Session("email") = "global_saidychan@sina.com" Session("tel") = "global_130000121553" End Sub </script> application\session.aspx文件: <html> <script language="VB" runat="server"> '返回Session值方法: Function getinfo(Key As String) As String Return Session(Key).ToString() End Function </script> <body > <br><br><br> <center> <h3><font face="Verdana">.NET->Session</font></h3> </center> <br><br> <center> <b><a href="info.aspx">员工档案!</a></b><p> <div align="center"> <center> <table border="0" width="35%" cellspacing="0" cellpadding="0"> <tr> <td width="50%">名称:</td> <td width="50%"><%=getinfo("name")%></td> </tr> <tr> <td width="50%">邮箱:</td> <td width="50%"><%=getinfo("email")%></td> </tr> <tr> <td width="50%">电话:</td> <td width="50%"><%=getinfo("tel")%></td> </tr> </table> </center> </div> </center> </body> </html> application\info.aspx文件: <html> <script language="VB" runat="server"> '取得上一页的信息 Sub Page_Load(Sender As Object, E As EventArgs) If Not (Page.IsPostBack) State("Referer") = Request.Headers("Referer") End If End Sub '按钮事件,把数据保存在Session中,并返回上一页 Sub sc(Sender As Object, E As EventArgs) Session("name") = name.Value Session("email") = email.Value Session("tel") = tel.Value Response.Redirect(State("Referer").ToString()) End Sub '按钮事件,返回上一页 Sub cc(Sender As Object, E As EventArgs) Response.Redirect(State("Referer").ToString()) End Sub </script> <body > <br> <br> <br> <center> <form runat="server"> <h3><font face="Verdana">.NET->Session!</font></h3> </center> <br> <br> <center> <b>选择你的信息: </b><p> <table bgcolor="#ccccff"> <tr> <td>名称:</td> <td> <select id="name" runat="server"> <option>saidy chan</option> <option>贺禧</option> <option>吕兵</option> </select> </td> </tr> <tr> <td>邮箱:</td> <td> <select id="email" runat="server"> <option>saidychan@sina.com</option> <option>chenyx@staff.yesky.com</option> <option>hexi1224@sina.com</option> </select> </td> </tr> <tr> <td>电话:</td> <td> <select id="tel" runat="server"> <option>023-77398202</option> <option>013011235488</option> <option>1398855566588</option> </select> </td> </tr> </table> <p> <input type="submit" OnServerClick="cc" Value="取消" runat="server"/> <input type="submit" OnServerClick="sc" Value="提交" runat="server"/> </form> </center> </body> </html>  我们看到页面把我们储存在Global.asax文件中的数据取出来了,我们点击“员工档案连接:  点击“提交“按钮“,我们看到下面的结果:  我们看到提交的结果是Session中保存的数据被替代了。 4.4.3 小结 利用几个例子讲述再网上非常有用的两个属性Application和Session,这两个属性非常重要,凡是做个一些网站的读者都知道的。 第五章 安全访问控制 asp.net中讨论安全性,首先要解决2个问题。那就是谁有权力进入系统?他进入系统以后能进行何种操作?在解决谁能进入系统的问题中,我们通常会维护一张允许进入系统的用户的名单,当用户要求进入的时候,我们判断他是否是合法用户。这样一来,问题就转化为如何有效地判别一个用户是否是系统的有效用户,我们称之为“验证“过程。一个常见的验证过程是,当我们进入某些系统时,被要求输入用户和口令。当用户进入以后,我们只允许他访问事先指定给他的资源,这一过程称为”授权“。只有通过授权检查后,用户才能够对相应资源进行操作。在asp.net环境中,asp.net和IIS结合在一起为用户提供验证和授权服务。 Asp.net的应用程序还可以根据进入用户的不同标识,执行相应不同的应用代码。这种方式被称为“角色扮演“(impersonation)。 在一些应用中,对于不同的用户所能够看到和执行的功能是不尽相同的,这就要求asp.net提供“角色“(Role)和”用户“(User)的区分方法。 4.5.1 验证和授权(Authentication And Authorization) asp.net和IIS一起为用户提供验证服务,用户验证方式有3种,即基本验证方式(basic)、简要验证方式(digest)、窗口验证方式(windows)。同时asp.net支持微软的”护照”(passport)验证服务,它单方面提供签到服务和用户描述服务。 此外,asp.net还提供了cookies,帮助建立一种基于用户Form的验证方式,通过cookies用户的应用程序可以用自己的代码和逻辑实现用户定义的可信性验证。 由于asp.net的验证服务是建立在IIS的验证服务之上的,因此在设立自己的应用服务的时候有时需要在IIS中进行相应的设置。例如:为实现asp.net的基本验证服务,就必须利用Internet Service Tool工具把该应用设置成基本鉴别服务方式。 具体方法为: 选择 ”开始”->”程序“->”管理工具“->”Internet信息服务器“ 打开”默认Web站点”,选择你的应用站点,比如:此处为”777“ 右击鼠标,选择”属性“,再选择”目录安全性“标签” 在”匿名访问和验证控制“框中,点击”编辑“按钮 然后在出现的”验证方法“窗口中,把”验证方法“框中,”基本验证“前面的选项打勾 最后确认,就完成了设置基本验证方法 操作的画面如下:  要使Asp.Net的验证机制生效,我们需要对应用的配置文件config.web进行设置。设置验证需要包含在<security>和</security>标识之间。它使用<authentication mode=”…”>语法形式,其中mode属性指定了验证采用的方式,具体的验证模式如下表格所示: 模 式 描 述  None 没有任何Asp.Net的验证服务被激活。  Windows Asp.Net和Windows的机制一起配合使用,可以授权限制windiows Nt的用户和工作组的访问。  Cookie Asp.Net 验证服务可以管理cookies,可以引导使一个未经授权的用户去登录网页。这种模式经常和IIS一起配合,可以让一个匿名用户去访问应用程序。  Passport Asp.Net验证服务通过使用护照(passport)服务软件包,附属在服务的外层,更加强了验证服务,这种软件包必须安装到系统中才能使用。   举例说来,使用Cookie验证方式对某个应用进行验证,那么在其应用的配置文件config.web中,应该含有一下几行: <!--config.web--> … <configuration> … <security> … <authentication mode="Cookie"/> …. </security> … </configuration> … asp.net提供了两种授权方式:基于ACL、资源权限的授权方式和URL授权。基于ACL和资源权限的授权方式有点类似于Unix下的文件权限检查,不过它更加严格和完备,当用户请求某个页面时,asp.net检查该页面的ACL(访问控制列表)和该文件的权限,看该用户是否有权限读取该页面。有,则该页面称作“已授权“。这种授权方式主要通过系统管理员对文件的权限的设定来实现。 而URL授权,对于某个用户的页面请求,并不是从文件权限出发,而是根据系统的配置情况,来决定用户的请求是否是经过授权的。URL授权的方式的实现通常是通过设置应用配置文件config.web中关于授权和角色的配置节来实现的。 4.5.2 基于WINDOWS的验证 当采用基于windows方式的验证以后(<authentication mode=”windows” />),asp.net对每一个页面请求产生一个WindowsPrincipal对象User,这个对象可以被URL授权方式用来进行授权,或者是被用户程序用来判断是否是某种角色。 例如,判断当前用户是否是管理员,可以采用以下的代码: If User.IsInRole(“Administrator”) ‘如果是管理员组成员,… … Else ‘如果不是管理员组成员,… … End If 可能用户希望对验证过程加入一些自己的控制代码,那么就需要对WindowsPrincipal对象的WindowsAuthentication_OnAuthenticate事件作出自己的处理,编写自己的消息处理函数。通常用户通过实现System.Security.Principal.Iprincipal类来完成。 4.5.3 基于FORM的验证 基于FORM的验证,实际上是允许应用程序定义自己的验证画面和可信性验证。当用户进入时,出现事先定义的画面并请求输入验证要素,输入完毕,用用户逻辑对输入验证,通过,则进入应用,否则,返回起始输入画面。基于FORM的验证,通常都采用cookies技术来实现验证任务。启用基于FORM的验证,是在config.web中设置<authentication mode=”Cookie” />来实现的。 例如:采用基于Form的验证方式,拒绝匿名用户进入的配置段如下: <!--config.web-> … <configuration> <security> <authentication mode="Cookie"/> <authorization> <deny users="?" /> </authorization> </security> </configuration> … 其中,<authorization>一节中,用deny标识表示禁止某种用户,“?”代表匿名用户,“*”代表所有用户,当然在users后也可以跟指定的用户,表示只拒绝指定的用户。 此外,在配置节中还有一个cookie标识,它规定了Cookie的行为,也较为重要。Cookie标识有三个属性: ·decryptionkey 用于指定对cookie加解密的密钥。如果不指定或指定为autogenerate,密钥将采用Crypto API产生的系统密钥。当指定为autogenerate时,产生的密钥和机器相关,因而不能跨机器和平台,除非显示给出密钥。 ·loginurl 验证页面。当用户验证失败以后,被定向到的页面,它可以是在本地,也可以是其他机器上。 ·cookie 指定用于验证任务的cookie的名字。由于在同一台机器上,可能存在多个应用,而同一应用使用一个cookie名,所以同一机器上的cookie名字不能相同。 例如,在config.web中有如下定义: <!--config.web --> … <security> <authentication mode="Cookie"> <cookie decryptionkey="autogenerate" loginurl="login.aspx" cookie=".ASPXCOOKIEDEMO" /> </authentication> </security> … 从这段配置,我们可以知道cookie的密钥由系统产生,当验证失败以后,页面将跳转至login.aspx,cook名为“.ASPXCOOKIEDEMO” 在基于FORM的验证中,一个常用到的对象是CookAuthentication。 CookAuthentication有4个比较重要的方法: ·RedirectFromLoginPage方法,它通常在验证成功以后,从用户的验证画面返回用户开始请求的页面。它带有两个参数,第一个为cookie要记录的用户名,第二个表明是否记录到永久性cookie中。 例如: CookieAuthentication.RedirectFromLoginPage(“Chen”,True) 表示把用户“Chen”记录到硬盘上的cookie记录中,然后跳转到用户原先请求的页面上。 ·GetAuthCookie 从cookie中取得指定用户名的值。它的参数和RedirectFromLoginPage方法是一样的。 例如: CookieAuthentication.GetAuthCookie(“Chen”,Flase) 表示从当前连接的cookie中取出用户名为chen的值 ·SetAuthCookie 把指定用户名存入cookie中。参数和GetAuthCookie方法一致 例如: CookieAuthentication.SetAuthCookie(“Chen”,Flase) 表示把用户“Chen”记录到连接过程中存在的cookie中 ·SignOut 删除当前用户的验证Cookie,它不会理会Cookie到底是在内存,还是在硬盘上。 下面我将介绍一个完整的例子: application\delault.aspx文件: <%@ Import Namespace="System.Web.Security " %> <html> <script language="VB" runat=server> Sub Page_Load(Src As Object, E As EventArgs) Welcome.Text = "Hello, " + User.Identity.Name End Sub Sub Signout_Click(Src As Object, E As EventArgs) CookieAuthentication.SignOut() ‘删去Cookies Response.Redirect("login.aspx") ‘返回验证画面 End Sub </script> <body> <h3><font face="Verdana">使用Cookie验证方式</font></h3> <form runat=server> <h3><asp:label id="Welcome" runat=server/></h3> <asp:button text="Signout" OnClick="Signout_Click" runat=server/> </form> </body> </html> application\login.aspx文件: <%@ Import Namespace="System.Web.Security " %> <html> <script language="VB" runat=server> Sub Login_Click(Src As Object, E As EventArgs) If (UserEmail.Value = "test@263.net" Or UserEmail.Value = "try@163.net") And UserPass.Value = "password" ‘如果用户为test@263.net或者是try@163.net而且口令为password,就认为通过验证 CookieAuthentication.RedirectFromLoginPage(UserEmail.Value, PersistCookie.Checked) ‘记录Cookie并且跳转到请求的页面 Else Msg.Text = "非法用户或口令: 请重试" End If End Sub </script> <body> <form runat=server> <h3><font face="Verdana">登录窗口</font></h3> <table> <tr> <td>Email地址:</td> <td><input id="UserEmail" type="text" runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="UserEmail" Display="Static" ErrorMessage="*" runat=server/></td> </tr> <tr> <td>口令:</td> <td><input id="UserPass" type=password runat=server/></td> <td><ASP:RequiredFieldValidator ControlToValidate="UserPass" Display="Static" ErrorMessage="*" runat=server/></td> </tr> <tr> <td>永久性Cookie:</td> <td><ASP:CheckBox id=PersistCookie runat="server" /> </td> <td></td> </tr> </table> <asp:button text="Login" OnClick="Login_Click" runat=server/> <p> <asp:Label id="Msg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server /> </form> </body> </html> config.web文件: <configuration> <security> <authentication mode="Cookie"> <!--采用cookie验证方式--> <cookie decryptionkey = "autogenerate" loginurl = "login.aspx" cookie = ".ASPXUSERDEMO" /> <!--密钥系统产生,登录页面为login.aspx,记录的Cookie名为.aspuserdemo--> </authentication> <authorization> <deny users="test@263.net" /> <!--虽然程序中有两个用户test@263和try@163.net可以进入,但此处封掉test@263.net,观察deny标识是否有效--> <deny users="?" /> <!--拒绝匿名用户anonymous--> </authorization> </security> <globalization requestencoding="UTF-8" responseencoding="UTF-8" /> </configuration> 我们还可以在config.web中设置用户和密码,当用户在验证窗口输入用户和密码后,将其带入CookieAuthenticationManager.Authenticate,有它来验证是否是合法用户。 在config.web中设置用户和密码使用credentials标识,它有一个属性passwordformat,决定口令存储的方式。Passwordformat可以为以下值: ·Clear 口令以纯文本方式存储。 ·SHA1 口令以SHA1方式存储。 ·MD5 口令以MD5方式存储。 例如: 在一个配置文件中, <!--config.web--> … <configuration> … <security> <authentication> <credentials passwordformat=”SHA1” > <user name=”Li” password=”GASDFSA9823598ASDBAD”/> <user name=”Chen” password=”ZASDFADSFASD23483142”/> </credentials> </authentication> </security> … </configuration> 从这个例子,我们看到credentials标识中的passwordformat为SHA1,所以下面的用户的密码是以SHA1方式加密以后的格式。在<credentials>和</credentials>之间我们定义了两个用户“Chen”和”Li”,其密码不可识别。 4.5.4 授权用户和角色 URL授权控制对资源的访问权限。它可以使一些用户和角色对资源有存取权限,也可以拒绝某些用户和角色对资源的存取。甚至它还可以决定能够存取资源的HTTP方法(例如:不允许get,允许POST等等)。 对于授权用户和角色的控制,asp.net通过配置文件config.web中的<authorization>标识段来实现。<allow>标识表示允许对资源的访问,<deny>标识表示拒绝对资源的访问。 它们都有两个属性,users和roles分别表示用户和角色。 我们来看一个实例: <!--config.web-> … <configuration> <security> <authorization> <allow users="nobody@163.net" /> <allow roles="Admins" /> <deny users="*" /> </authorization> </security> </configuration> … 它表明了这样一个事实,用户“nobody@163.net“和角色Admins有访问本站点的权力,其他用户对本站点的访问将被拒绝。也就是用户nobody@163.net和角色Admins分别是授权用户和授权角色。 同样,我们可以定义多个用户或者角色被授权或禁止,它们之间以“,“分隔。 例如: … <allow users=”Chen,Li,Wang” /> <deny roles=”Admins,Everyone” /> … 表示用户“Chen”、“Li”、”Wang”是授权用户,但是角色为“Admins”或者是”Everyone”的被排除在外。 它的效果和分开写是一样的,如上例也可以写为: … <allow users=”Chen” /> <allow users=”Li” /> <allow users=”Wang” /> <deny roles=”Admins” /> <deny roles=”Everyone” /> … 此外,还可以决定用户的某种HTTP方法是否可以被允许,方法是使用verb属性来表明对那种HTTP方法操作。 例如: … <allow verb=post users=”Chen,Li” /> <deny verb=get roles=”everyone” /> … 表示允许用户“Chen”,”Li“采用post方法访问资源,而拒绝角色everyone的get方式对资源的访问。 符号“*“和”?“在<allow>和<deny>标识中有特殊的含义。”*“表示任何用户,”?“表示匿名用户。 例如: … <authorization> <allow users=”*” /> <deny users=”?” /> </authorization> 表示除了匿名用户以外的所有用户都被允许访问本站点。 由前面的学习我们知道,在asp.net中应用是树型分层的,所以其配置文件也是呈层次结构,这也就导致了用户和角色的授权不是单一的结果,它要取决于沿树型结构上所有配置文件指定的结果的合集,而且越接近叶节点的配置越是有效。 例如:访问http:www.my.com/MyApp/a.aspx 在http:www.my.com的根目录下的配置文件config.web有如下内容: … <security> <authorization> <allow users=”*” /> </authorization> </security> … 而在MyApp目录下有配置文件config.web内容如下: … <security> <authorization> <allow users=”Chen” /> <deny users=”*” /> </authorization> <security> … 那么,授权用户的集合到底是怎样的呢?asp.net首先取得站点根目录下的配置,即所有用户都被允许访问,然后asp.net进入Myapp的目录取得其下的配置,除用户“Chen”以外所有的用户被拒绝,最后合并两个授权集合,并且如果两者之间有冲突,以后者为准。所以最终的授权集合为用户“Chen”,其他用户被拒绝。 第六章 会员系统例子: 4.6.1 数据库: 我们建立两个表City和Customer,在建立几个存储过程来操作数据库(member.sql): CREATE TABLE [dbo].[City] ( [ID] [int] NOT NULL , [Name] [nvarchar] (20) NULL ) ON [PRIMARY] GO CREATE TABLE [dbo].[customer] ( [ID] [int] IDENTITY (1, 1) NOT NULL , [Name] [nvarchar] (30) NULL , [sex] [bit] NOT NULL , [Birth] [smalldatetime] NULL , [City] [int] NULL , [Zip] [nvarchar] (6) NULL , [Address] [nvarchar] (50) NULL , [Telephone] [nvarchar] (30) NULL , [PIN] [nvarchar] (30) NULL , [Password] [nvarchar] (30) NULL , [EMail] [nvarchar] (30) NULL , [Question] [nvarchar] (50) NULL , [Answer] [nvarchar] (50) NULL ) ON [PRIMARY] GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO CREATE PROCEDURE [GetAllCities] AS Select [ID],[Name] From City GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO CREATE PROCEDURE [GetDetailByID] @ID Int AS Select PIN,Password,[Name],Birth,Sex,City,Zip,EMail,Telephone,Address,Question,Answer,[ID] From Customer Where [ID]=@ID GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO CREATE PROCEDURE [GetDetailByPIN] @PIN NVarChar(30) AS Select PIN,Password,[Name],Birth,Sex,City,Zip,EMail,Telephone,Address,Question,Answer,[ID] From Customer Where [PIN]=@PIN GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON GO CREATE PROCEDURE [IsValidUser] @PIN NVarChar(30), @Password NVarChar(30), @ID Int Output AS Select @ID=[ID] From Customer Where PIN=@PIN and Password=@Password GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO CREATE PROCEDURE [Modify] @ID Int, @PIN NVarCHar(30), @Password NVarCHar(30), @Name NVarCHar(30), @Birth DateTime, @Sex bit, @City int, @Zip NVarCHar(6), @EMail NVarCHar(30), @Telephone NVarCHar(30), @Address NVarCHar(30), @Question NVarCHar(50), @Answer NVarCHar(50) AS Update Customer Set Password=@Password,[Name]=@Name,Birth=@Birth,Sex=@Sex,City=@City,Zip=@Zip,EMail=@EMail,Telephone=@Telephone,Address=@Address,Question=@Question,Answer=@Answer Where ID=@ID And PIN=@PIN GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON GO CREATE PROCEDURE [PromptPassword] @PIN nvarchar(30), @Answer nvarchar(50), @Password nvarchar(30) output AS select @Password=Password From Customer Where PIN=@PIN And Answer=@Answer GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO CREATE PROCEDURE [PromptQuestion] @PIN nvarchar(30), @Question nvarchar(50) output AS select @Question=Question From Customer Where PIN=@PIN GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO CREATE PROCEDURE [Register] @ID Int OUTPUT, @PIN NVarCHar(30), @Password NVarCHar(30), @Name NVarCHar(30), @Birth DateTime, @Sex bit, @City int, @Zip NVarCHar(6), @EMail NVarCHar(30), @Telephone NVarCHar(30), @Address NVarCHar(30), @Question NVarCHar(50), @Answer NVarCHar(50) AS Insert Into Customer (PIN,Password,[Name],Birth,Sex,City,Zip,EMail,Telephone,Address,Question,Answer) Values (@PIN,@Password,@Name,@Birth,@Sex,@City,@Zip,@EMail,@Telephone,@Address,@Question,@Answer) SELECT @ID = @@IDENTITY GO SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON GO 4.6.2 登录页面: 判断用户的Pin和密码是否正确,并且是注册和密码提示的入口: (csbook\appsoft\member\login.aspx) <%@ Page EnableSessionState="False" MaintainState="false" Debug="True"%> <%@ Import Namespace="DarkMan" %> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) RegisterLink.NavigateUrl="register.aspx?ReturnUrl="+Request.Params("ReturnUrl") PromptPasswordLink.NavigateUrl="prompt.aspx?ReturnUrl="+Request.Params("ReturnUrl") End Sub Sub OnLogin(sender As Object, e As EventArgs) Dim theDB As New MemberDB Try Dim theID As Integer = theDB.IsValidUser(CStr(pin.Text),CStr(password1.Text)) CookieAuthentication.SetAuthCookie(tehID, false) Page.Navigate("modify.aspx") Catch e1 As Exception Prompt.Text="登录失败!" End Try End Sub </script> <HTML> <BODY> <DIV Align="Center"> <H1>会员登录</H1> <hr wifth=600> </DIV> <FORM RunAt="Server"> <TABLE WIDTH=600 BORDER=0 CELLSPACING=1 CELLPADDING=1 Align="Center"> <TR> <TD COLSPAN="2"> <asp:RegularExpressionValidator id="RegPin" runat="server" ControlToValidate="pin" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 帐号中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="2"> <asp:RegularExpressionValidator id="RegPassword" runat="server" ControlToValidate="password1" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 密码中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD>账号</TD> <TD><asp:textbox id="pin" RunAt="server"/> <asp:RequiredFieldValidator id="RFpin" runat="server" ControlToValidate="pin" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD>密码</TD> <TD><asp:textbox id="password1" RunAt="server" TextMode="Password"/> <asp:RequiredFieldValidator id="RFpass" runat="server" ControlToValidate="password1" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="2"><asp:label id="Prompt" RunAt="Server"/> </TD> </TR> <TR> <TD COLSPAN="2"> <input type="submit" OnServerClick="OnLogin" Value="马上登录" runat="server"/> <asp:Hyperlink id="RegisterLink" runat="server" Text="我要注册" /> <asp:Hyperlink id="PromptPasswordLink" runat="server" Text="密码提示" /> </TD> </TR> </TABLE> </FORM> </BODY> </HTML> 4.6.3 注册页面: (csbook\appsoft\member\register.aspx): <%@ Page EnableSessionState="False" MaintainState="false" Debug="True"%> <%@ Import Namespace="DarkMan" %> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not Page.IsPostBack Then Dim result As SQLDataReaderResult Dim obj As New City result = obj.GetAll() city.DataSource=result.dr city.DataBind result.Close End If End Sub Sub OnRegister(sender As Object, e As EventArgs) If Page.IsValid Then Dim theUser As New MemberDetail theUser.PIN = pin.Text theUser.Password = password1.Text theUser.Name = name.Text theUser.Birth = DateTime.Parse(birth.Text) theUser.Sex = sex.SelectedItem.Value If city.SelectedItem<>DBNull Then theUser.City = city.SelectedItem.Value End If theUser.Zip = zip.Text theUser.EMail = email.Text theUser.Telephone = telephone.Text theUser.Address = address.Text theUser.Question = question.Text theUser.Answer = answer.Text Try Dim theDB As New MemberDB Dim theID As Integer = theDB.Register(theUser) Page.Navigate( Request.Params("ReturnUrl") ) Catch e1 As Exception ErrMsg.Text="注册失败" End Try End If End Sub </script> <HTML> <BODY> <DIV Align="Center"> <H1>会员注册</H1> <hr wifth=600> </DIV> <FORM RunAt="Server"> <TABLE WIDTH=600 BORDER=0 CELLSPACING=1 CELLPADDING=1 Align="Center"> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegPin" runat="server" ControlToValidate="pin" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 帐号中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegName" runat="server" ControlToValidate="name" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 姓名中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegPassword" runat="server" ControlToValidate="password1" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 密码中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegBirth" runat="server" ControlToValidate="birth" ValidationExpression="^\d{4}-\d{1,2}-\d{1,2}$" Display="Dynamic"> 日期格式:2001-7-01 </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="Regzip" runat="server" ControlToValidate="zip" ValidationExpression="^\d{6}$" Display="Dynamic"> 邮政编码不对 </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="Regtel" runat="server" ControlToValidate="telephone" ValidationExpression="^[\d-\(\)]+$" Display="Dynamic"> 电话号码不对 </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegEMail" runat="server" ControlToValidate="email" ValidationExpression="^[\w-_.]*[\w-_.]@[\w].+[\w]+[\w]$" Display="Dynamic"> EMail格式:xxx@222.com </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:CompareValidator id="CompPassword12" ControlToValidate="password2" ControlToCompare = "password1" Display="Dynamic" Type="String" runat="server"> 密码校验不正确! </asp:CompareValidator> </TD> </TR> <TR> <TD>账号</TD> <TD><asp:textbox id="pin" RunAt="server"/> <asp:RequiredFieldValidator id="RFpin" runat="server" ControlToValidate="pin" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TD>姓名</TD> <TD><asp:textbox id="name" RunAt="server"/> <asp:RequiredFieldValidator id="RFname" runat="server" ControlToValidate="name" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD>密码</TD> <TD><asp:textbox id="password1" RunAt="server" TextMode="Password"/> <asp:RequiredFieldValidator id="RFpass" runat="server" ControlToValidate="password1" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TD>密码校验</TD> <TD><asp:textbox id="password2" RunAt="server" TextMode="Password"/></TD> </TR> <TR> <TD>生日</TD> <TD><asp:textbox id="birth" RunAt="server"/></TD> <TD>性别</TD> <TD> <asp:RadioButtonList RepeatColumns="2" id="sex" runat="server"> <asp:ListItem text="男" value="0" Selected/> <asp:ListItem text="女" value="1"/> </asp:RadioButtonList></TD> </TR> <TR> <TD>城市</TD> <TD> <asp:DropDownList id="city" runat="server" DataTextField="Name" DataValueField="ID" /> </TD> <TD>邮政编码</TD> <TD><asp:textbox id="zip" RunAt="server"/> <asp:RequiredFieldValidator id="RFzip" runat="server" ControlToValidate="zip" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD>EMail</TD> <TD><asp:textbox id="email" RunAt="server"/> <asp:RequiredFieldValidator id="RFemail" runat="server" ControlToValidate="email" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TD>电话</TD> <TD><asp:textbox id="telephone" RunAt="server"/> <asp:RequiredFieldValidator id="RFtel" runat="server" ControlToValidate="telephone" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="1">地址</TD> <TD COLSPAN="3"><asp:textbox id="address" RunAt="server" Columns="50"/> <asp:RequiredFieldValidator id="RFAdrress" runat="server" ControlToValidate="address" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="1">密码提示问题</TD> <TD COLSPAN="3"><asp:textbox id="question" RunAt="server" Columns="50"/> <asp:RequiredFieldValidator id="RFQ" runat="server" ControlToValidate="question" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="1">密码提示问题答案</TD> <TD COLSPAN="3"><asp:textbox id="answer" RunAt="server" Columns="50"/> <asp:RequiredFieldValidator id="RFA" runat="server" ControlToValidate="answer" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <input type="submit" OnServerClick="OnRegister" Value="马上注册" runat="server"/> <br> <font color="red"><asp:label id="ErrMsg" runat="server"/></font> </TD> </TR> </TABLE> </FORM> </BODY> </HTML> 4.6.4 修改页面: (csbook\appsoft\member\modify.aspx): <%@ Page EnableSessionState="False" MaintainState="false" Debug="True"%> <%@ Import Namespace="DarkMan" %> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not Page.IsPostBack Then Dim theDB As New MemberDB Dim m_PIN As String=Request.Params("PIN") Dim m_ID As Integer=CInt( Request.Params("ID") ) Dim theUser As MemberDetail If m_PIN=DBNull And m_ID=DBNull Then CookieAuthentication.RedirectFromLoginPage(theID, false) Else If m_PIN<>DBNull Then theUser=theDB.GetDetailByPIN(m_PIN) userid.Text = theUser.ID pin.Text=theUser.PIN password1.Text=theUser.Password name.Text=theUser.Name birth.Text=theUser.Birth zip.Text=theUser.Zip email.Text=theUser.EMail telephone.Text=theUser.Telephone address.Text=theUser.Address question.Text=theUser.Question answer.Text=theUser.Answer Else theUser=theDB.GetDetailByID(m_ID) userid.Text = theUser.ID pin.Text=theUser.PIN password1.Text=theUser.Password name.Text=theUser.Name birth.Text=theUser.Birth zip.Text=theUser.Zip email.Text=theUser.EMail telephone.Text=theUser.Telephone address.Text=theUser.Address question.Text=theUser.Question answer.Text=theUser.Answer End If Dim result As SQLDataReaderResult Dim obj As New City result = obj.GetAll() city.DataSource=result.dr city.DataBind result.Close End If End Sub Sub OnModify(sender As Object, e As EventArgs) If Page.IsValid Then Dim theUser As New MemberDetail theUser.ID = userid.Text theUser.PIN = pin.Text theUser.Password = password1.Text theUser.Name = name.Text theUser.Birth = DateTime.Parse(birth.Text) theUser.Sex = sex.SelectedItem.Value If city.SelectedItem<>DBNull Then theUser.City = city.SelectedItem.Value End If theUser.Zip = zip.Text theUser.EMail = email.Text theUser.Telephone = telephone.Text theUser.Address = address.Text theUser.Question = question.Text theUser.Answer = answer.Text Dim theDB As New MemberDB Dim theID As Integer = theDB.Modify(theUser) CookieAuthentication.RedirectFromLoginPage(theID, false) Page.Navigate("login.aspx") End If End Sub </script> <HTML> <BODY> <DIV Align="Center"> <H1>会员信息修改</H1> <hr wifth=600> </DIV> <FORM RunAt="Server"> <TABLE WIDTH=600 BORDER=0 CELLSPACING=1 CELLPADDING=1 Align="Center"> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegPin" runat="server" ControlToValidate="pin" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 帐号中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegName" runat="server" ControlToValidate="name" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 姓名中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegPassword" runat="server" ControlToValidate="password1" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 密码中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegBirth" runat="server" ControlToValidate="birth" ValidationExpression="^\d{4}-\d{1,2}-\d{1,2}$" Display="Dynamic"> 日期格式:2001-7-01 </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="Regzip" runat="server" ControlToValidate="zip" ValidationExpression="^\d{6}$" Display="Dynamic"> 邮政编码不对 </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="Regtel" runat="server" ControlToValidate="telephone" ValidationExpression="^[\d-\(\)]+$" Display="Dynamic"> 电话号码不对 </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegEMail" runat="server" ControlToValidate="email" ValidationExpression="^[\w-_.]*[\w-_.]@[\w].+[\w]+[\w]$" Display="Dynamic"> EMail格式:xxx@222.com </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <asp:CompareValidator id="CompPassword12" ControlToValidate="password2" ControlToCompare = "password1" Display="Dynamic" Type="String" runat="server"> 密码校验不正确! </asp:CompareValidator> </TD> </TR> <TR> <TD>账号</TD> <TD><asp:textbox id="pin" RunAt="server"/> <asp:RequiredFieldValidator id="RFpin" runat="server" ControlToValidate="pin" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TD>姓名</TD> <TD><asp:textbox id="name" RunAt="server"/> <asp:RequiredFieldValidator id="RFname" runat="server" ControlToValidate="name" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD>密码</TD> <TD><asp:textbox id="password1" RunAt="server" TextMode="Password"/> <asp:RequiredFieldValidator id="RFpass" runat="server" ControlToValidate="password1" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TD>密码校验</TD> <TD><asp:textbox id="password2" RunAt="server" TextMode="Password"/></TD> </TR> <TR> <TD>生日</TD> <TD><asp:textbox id="birth" RunAt="server"/></TD> <TD>性别</TD> <TD> <asp:RadioButtonList RepeatColumns="2" id="sex" runat="server"> <asp:ListItem text="男" value="0" Selected/> <asp:ListItem text="女" value="1"/> </asp:RadioButtonList></TD> </TR> <TR> <TD>城市</TD> <TD> <asp:DropDownList id="city" runat="server" DataTextField="Name" DataValueField="ID" /> </TD> <TD>邮政编码</TD> <TD><asp:textbox id="zip" RunAt="server"/> <asp:RequiredFieldValidator id="RFzip" runat="server" ControlToValidate="zip" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD>EMail</TD> <TD><asp:textbox id="email" RunAt="server"/> <asp:RequiredFieldValidator id="RFemail" runat="server" ControlToValidate="email" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TD>电话</TD> <TD><asp:textbox id="telephone" RunAt="server"/> <asp:RequiredFieldValidator id="RFtel" runat="server" ControlToValidate="telephone" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="1">地址</TD> <TD COLSPAN="3"><asp:textbox id="address" RunAt="server" Columns="50"/> <asp:RequiredFieldValidator id="RFAdrress" runat="server" ControlToValidate="address" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="1">密码提示问题</TD> <TD COLSPAN="3"><asp:textbox id="question" RunAt="server" Columns="50"/> <asp:RequiredFieldValidator id="RFQ" runat="server" ControlToValidate="question" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="1">密码提示问题答案</TD> <TD COLSPAN="3"><asp:textbox id="answer" RunAt="server" Columns="50"/> <asp:RequiredFieldValidator id="RFA" runat="server" ControlToValidate="answer" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> </TR> <TR> <TD COLSPAN="4"> <input type="submit" OnServerClick="OnModify" Value="马上提交" runat="server"/> </TD> </TR> </TABLE> <asp:textbox id="userid" RunAt="server" Columns="0" width="0" height="0"/> </FORM> </BODY> </HTML> 4.6.5 密码提示页面: 当我们输入用户的Pin时,程序自动把用户的提问问题显示出来,如果没有这个用户,则提示没有这个用户(csbook\appsoft\member\prompt.aspx): <%@ Page EnableSessionState="False" MaintainState="false" Debug="True"%> <%@ Import Namespace="DarkMan" %> <script language="VB" runat="server"> Sub OnPromptQuestion(sender As Object, e As EventArgs) If Page.IsValid Then Try Dim theDB As New MemberDB question.Text = theDB.PromptQuestion(pin.Text) Dim obj As New RequiredFieldValidator() obj.ControlToValidate="answer" obj.ErrorMessage = "需要输入密码问题答案!" Panel.Controls.Add(obj) Catch e1 As Exception password.Text = "不存在此账号!" End Try End If End Sub Sub OnPromptPassword(sender As Object, e As EventArgs) m_Answer = answer.Text If Not Page.IsValid Or m_Answer=DBNull Then Exit Sub Dim theDB As New MemberDB Dim m_Password As String Try m_Password = theDB.PromptPassword(pin.Text,answer.Text) If m_Password <> DBNull Then password.Text = "你的密码是:"+m_Password+"<a href="+Request.Params("ReturnUrl")+">现在返回</A>" Else password.Text = "无法提示你的密码。可能你没有正确地回答问题!" End If Catch e1 As Exception password.Text = "无法提示你的密码。可能你没有正确地回答问题!" Exit Sub End Try End Sub </script> <HTML> <BODY> <DIV Align="Center"> <H1>会员注册</H1> <hr wifth=600> </DIV> <FORM RunAt="Server"> <TABLE WIDTH=600 BORDER=0 CELLSPACING=1 CELLPADDING=1 Align="Center"> <TR> <TD COLSPAN="4"> <asp:RegularExpressionValidator id="RegPin" runat="server" ControlToValidate="pin" ValidationExpression="^[\S^']{6,30}$" Display="Dynamic"> 帐号中:某些特殊字符禁用!另外,必须至少6个字符! </asp:RegularExpressionValidator> </TD> </TR> <TR> <TD>账号</TD> <TD><asp:textbox id="pin" RunAt="server" OnTextChanged="OnPromptQuestion" AutoPostBack="True"/> <asp:RequiredFieldValidator id="RFpin" runat="server" ControlToValidate="pin" ErrorMessage="*" ForeColor="Red"> </asp:RequiredFieldValidator> </TD> <TR> <TD COLSPAN="1">密码提示问题</TD> <TD COLSPAN="3"><asp:textbox id="question" RunAt="server" Columns="50" ReadOnly/> </TD> </TR> <TR> <TD COLSPAN="1">密码提示问题答案</TD> <TD COLSPAN="3"><asp:textbox id="answer" RunAt="server" Columns="50"/> <asp:Panel id="Panel" runat="server"/> </TD> </TR> <TR> <TD COLSPAN="4"><font color='red'> <asp:label id="password" runat="server"/></font> </TD> </TR> <TR> <TD COLSPAN="4"> <input type="submit" OnServerClick="OnPromptPassword" Value="请马上提示" runat="server"/> </TD> </TR> </TABLE> </FORM> </BODY> </HTML> 4.6.6 连接数据库组件方法: 通过这个组件,我们获得在配置文件Config.web中的数据库的连接串,(csbook\appsoft\member\DBConn\DBConn.vb): Imports System Imports System.Data Imports System.Data.SQL Imports System.Web Imports System.Collections Namespace DarkMan Public Class DBConn Shared m_ConnectionString As String Shared ReadOnly Property ConnectionString As String Get If m_ConnectionString = "" Then Dim appsetting As Hashtable = CType(HttpContext.Current.GetConfig("appsettings"), Hashtable) m_ConnectionString = CStr(appsetting("DSN")) If m_ConnectionString = "" Then throw new Exception("iShop DSN Value not set in Config.web") End if End If return m_connectionString End Get End Property End Class Public Class SQLDataReaderResult Public conn As SQLConnection Public dr As SQLDataReader Public Sub Close() If conn.State = DBObjectState.Open then Try dr.Close() conn.Close() Catch e As Exception throw e End Try End If End Sub End Class End Namespace 4.6.7 操作组件方法: 这个组件里封装了对数据的插入、更新、密码提示方法、用户有效性的判断等方法。 csbook\appsoft\member\com\member.vb: Imports System Imports System.Data Imports System.Data.SQL Namespace DarkMan Public Class MemberDetail Public ID As Integer Public PIN As String Public Password As String Public Name As String Public Birth As DateTime Public Sex As Boolean Public City As Integer Public Zip As String Public EMail As String Public Telephone As String Public Address As String Public Question As String Public Answer As String End Class Public Class City Public Shared Function GetAll() As SQLDataReaderResult Dim myConnection As SQLConnection = new SQLConnection(DarkMan.DBConn.ConnectionString) Dim myCommand As SQLCommand=New SQLCommand("GetAllCities", myConnection) myCommand.CommandType = CommandType.StoredProcedure Dim result As New SQLDataReaderResult result.Conn = myConnection Try myConnection.Open() myCommand.Execute(result.dr) Catch e As Exception throw e End Try return result End Function End Class Public Class MemberDB '登记信息 Public Function Register(ByRef user As MemberDetail) As Integer Return RegNMod(0,user) End Function '密码提示 Public Function PromptPassword(ByVal PIN As String,ByVal Answer As String) As String Dim myConnection As SQLConnection = new SQLConnection(DarkMan.DBConn.ConnectionString) Dim myCommand As SQLCommand= new SQLCommand("PromptPassword", myConnection) myCommand.CommandType = CommandType.StoredProcedure Dim param As SQLParameter Param = new SQLParameter("@PIN", SQLDataType.NVarChar,30) Param.Value = PIN myCommand.Parameters.Add(Param) Param = new SQLParameter("@Answer", SQLDataType.NVarChar,50) Param.Value = Answer myCommand.Parameters.Add(Param) Param = new SQLParameter("@Password", SQLDataType.NVarChar,30) Param.Direction = ParameterDirection.Output myCommand.Parameters.Add(Param) Try myConnection.Open() myCommand.Execute() Catch e As Exception throw e Finally If myConnection.State = DBObjectState.Open then myConnection.Close() End If End Try return CStr( Param.Value ) End Function '密码问题提示 Public Function PromptQuestion(ByVal PIN As String) As String Dim myConnection As SQLConnection = new SQLConnection(DarkMan.DBConn.ConnectionString) Dim myCommand As SQLCommand= new SQLCommand("PromptQuestion", myConnection) myCommand.CommandType = CommandType.StoredProcedure Dim param As SQLParameter Param = new SQLParameter("@PIN", SQLDataType.NVarChar,30) Param.Value = PIN myCommand.Parameters.Add(Param) Param = new SQLParameter("@Question", SQLDataType.NVarChar,50) Param.Direction = ParameterDirection.Output myCommand.Parameters.Add(Param) Try myConnection.Open() myCommand.Execute() Catch e As Exception throw e Finally If myConnection.State = DBObjectState.Open then myConnection.Close() End If End Try return CStr( Param.Value ) End Function '修改信息 Public Function Modify(ByRef user As MemberDetail) As Integer Return RegNMod(1,user) End Function Public Function GetDetailByID(ByVal ID As Integer) As MemberDetail return GetDetail(0,ID) End Function Public Function GetDetailByPIN(ByVal PIN As String) As MemberDetail return GetDetail(1,,PIN) End Function '判断是否为合法用户 Public Function IsValidUser(ByVal PIN As String,ByVal Password As String) As Integer Dim myConnection As SQLConnection = new SQLConnection(DarkMan.DBConn.ConnectionString) Dim myCommand As SQLCommand= new SQLCommand("IsValidUser", myConnection) myCommand.CommandType = CommandType.StoredProcedure Dim param As SQLParameter Param = new SQLParameter("@PIN", SQLDataType.NVarChar,30) Param.Value = PIN myCommand.Parameters.Add(Param) Param = new SQLParameter("@Password", SQLDataType.NVarChar,30) Param.Value = Password myCommand.Parameters.Add(Param) Param = new SQLParameter("@ID", SQLDataType.Int) Param.Direction = ParameterDirection.Output myCommand.Parameters.Add(Param) Try myConnection.Open() myCommand.Execute() Catch e As Exception throw e Finally If myConnection.State = DBObjectState.Open then myConnection.Close() End If End Try return CInt( Param.Value ) End Function Protected Function GetDetail(ByVal op As Integer,Optional ByVal ID As Integer=0,Optional ByVal PIN As String="") As MemberDetail Dim theUser As MemberDetail=New MemberDetail Dim myConnection As SQLConnection = new SQLConnection(DarkMan.DBConn.ConnectionString) Dim myCommand As SQLCommand Select Case op Case 0 'By ID myCommand = new SQLCommand("GetDetailByID", myConnection) Dim param As SQLParameter Param = new SQLParameter("@ID", SQLDataType.Int) Param.Value = ID myCommand.Parameters.Add(Param) Case 1 'By PIN myCommand = new SQLCommand("GetDetailByPIN", myConnection) Dim param As SQLParameter Param = new SQLParameter("@PIN", SQLDataType.Int) Param.Value = PIN myCommand.Parameters.Add(Param) Case Else Exit Function End Select myCommand.CommandType = CommandType.StoredProcedure Dim dr As SQLDataReader Try myConnection.Open() myCommand.Execute(dr) If dr.Read Then theUser.PIN = dr.GetString(0) 'dr.GetValue(0,theUser.PIN) theUser.Password = dr.GetString(1) 'dr.GetValue(1,theUser.Password) theUser.Name = dr.GetString(2) 'dr.GetValue(2,theUser.Name) theUser.Birth = dr.GetDateTime(3) 'dr.GetValue(3,theUser.Birth) theUser.Sex = dr.GetSQLBit(4).BoolValue 'dr.GetValue(4,theUser.Sex) theUser.City = dr.GetInt32(5) 'dr.GetValue(5,theUser.City) theUser.Zip = dr.GetString(6) 'dr.GetValue(6,theUser.Zip) theUser.EMail = dr.GetString(7) 'dr.GetValue(7,theUser.EMail) theUser.Telephone = dr.GetString(8) 'dr.GetValue(8,theUser.Telephone) theUser.Address = dr.GetString(9) 'dr.GetValue(9,theUser.Address) theUser.Question = dr.GetString(10) 'dr.GetValue(10,theUser.Question) theUser.Answer = dr.GetString(11) 'dr.GetValue(11,theUser.Answer) theUser.ID = dr.GetInt32(12) 'dr.GetValue(0,theUser.ID) End If Catch e As Exception throw e Finally If myConnection.State = DBObjectState.Open then myConnection.Close() End If End Try Return theUser End Function Protected Function RegNMod( ByVal op As Integer,ByRef user As MemberDetail) As Integer Dim myConnection As SQLConnection = new SQLConnection(DarkMan.DBConn.ConnectionString) Dim myCommand As SQLCommand Dim ParamID As New SQLParameter("@ID", SQLDataType.Int) Select Case op Case 0 'Insert myCommand = new SQLCommand("Register", myConnection) ParamID.Direction = ParameterDirection.Output myCommand.Parameters.Add(ParamID) Case 1 'Modify myCommand = new SQLCommand("Modify", myConnection) ParamID.Value = user.ID myCommand.Parameters.Add(ParamID) Case Else Exit Function End Select myCommand.CommandType = CommandType.StoredProcedure Dim param As SQLParameter Param = new SQLParameter("@PIN", SQLDataType.NVarChar, 30) Param.Value = user.PIN myCommand.Parameters.Add(Param) Param = new SQLParameter("@Password", SQLDataType.NVarChar, 30) Param.Value = user.Password myCommand.Parameters.Add(Param) Param = new SQLParameter("@Name", SQLDataType.NVarChar, 30) Param.Value = user.Name myCommand.Parameters.Add(Param) Param = new SQLParameter("@Birth", SQLDataType.SmallDateTime) Param.Value = user.Birth myCommand.Parameters.Add(Param) Param = new SQLParameter("@Sex", SQLDataType.Bit) Param.Value = user.Sex myCommand.Parameters.Add(Param) Param = new SQLParameter("@City", SQLDataType.Int) Param.Value = user.City myCommand.Parameters.Add(Param) Param = new SQLParameter("@Zip", SQLDataType.NVarChar, 6) Param.Value = user.Zip myCommand.Parameters.Add(Param) Param = new SQLParameter("@EMail", SQLDataType.NVarChar, 30) Param.Value = user.EMail myCommand.Parameters.Add(Param) Param = new SQLParameter("@Telephone", SQLDataType.NVarChar, 30) Param.Value = user.Telephone myCommand.Parameters.Add(Param) Param = new SQLParameter("@Address", SQLDataType.NVarChar, 50) Param.Value = user.Address myCommand.Parameters.Add(Param) Param = new SQLParameter("@Question", SQLDataType.NVarChar, 50) Param.Value = user.Question myCommand.Parameters.Add(Param) Param = new SQLParameter("@Answer", SQLDataType.NVarChar, 50) Param.Value = user.Answer myCommand.Parameters.Add(Param) Try myConnection.Open() myCommand.Execute() Catch e As Exception throw e Finally If myConnection.State = DBObjectState.Open then myConnection.Close() End If End Try If op=0 Then return CInt(ParamID.Value) Else return user.ID End If End Function End Class End Namespace 4.6.8 配置文件: 我们把数据库的连接字符串方法在配置文件Config.web里面: (csbook\appsoft\member\Config.web): <configuration> <!--数据库连接字符串 --> <appsettings> <add key="DSN" value="server=localhost;uid=sa;pwd=;database=darkman" /> </appsettings> <globalization requestencoding="gb2312" responseencoding="gb2312" /> </configuration> 4.6.9 运行效果: 登录页面:  密码提示页面:  4.6.10 小结 本章利用一个会员系统来讲述了一个利用.NET的Application的应用。