针对有网友说看不见文章内容, 现提示如下: 点击每一个标题行任一地方都会展开和隐藏此文章内容(不要点击标题). 目前展开隐藏功能只支持IE浏览器,虽然可以改成支持FF浏览器,不过现在一直没时间去弄,等有时间再修改了。 |
blog名称:乱闪Blog 日志总数:267 评论数量:1618 留言数量:-26 访问次数:2654864 建立时间:2005年1月1日 |
|

| |
SQL Server 存储过程的分页
|
建立表:
CREATE TABLE [TestTable] ( [ID] [int] IDENTITY (1, 1) NOT NULL , [FirstName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [LastName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [Country] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Note] [nvarchar] (2000) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY] GO
插入数据:(2万条,用更多的数据测试会明显一些) SET IDENTITY_INSERT TestTable ON
declare @i int set @i=1 while @i<=20000 begin insert into TestTable([id], FirstName, LastName, Country,Note) values(@i, 'FirstName_XXX','LastName_XXX','Country_XXX','Note_XXX') set @i=@i+1 end
SET IDENTITY_INSERT TestTable OFF
-------------------------------------
分页方案一:(利用Not In和SELECT TOP分页) 语句形式: SELECT TOP 10 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 20 id FROM TestTable ORDER BY id)) ORDER BY ID
SELECT TOP 页大小 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id)) ORDER BY ID
-------------------------------------
分页方案二:(利用ID大于多少和SELECT TOP分页) 语句形式: SELECT TOP 10 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 20 id FROM TestTable ORDER BY id) AS T)) ORDER BY ID
SELECT TOP 页大小 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id) AS T)) ORDER BY ID
-------------------------------------
分页方案三:(利用SQL的游标存储过程分页) create procedure XiaoZhengGe @sqlstr nvarchar(4000), --查询字符串 @currentpage int, --第N页 @pagesize int --每页行数 as set nocount on declare @P1 int, --P1是游标的id @rowcount int exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output select ceiling(1.0*@rowcount/@pagesize) as 总页数--,@rowcount as 总行数,@currentpage as 当前页 set @currentpage=(@currentpage-1)*@pagesize+1 exec sp_cursorfetch @P1,16,@currentpage,@pagesize exec sp_cursorclose @P1 set nocount off
其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。 建议优化的时候,加上主键和索引,查询效率会提高。
通过SQL 查询分析器,显示比较:我的结论是: 分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句 分页方案一:(利用Not In和SELECT TOP分页) 效率次之,需要拼接SQL语句 分页方案三:(利用SQL的游标存储过程分页) 效率最差,但是最为通用
在实际情况中,要具体分析。
转自: http://goaler.xicp.net/ShowLog.asp?ID=502 |
|
学会在ASP中使用存储过程
|
学习使用存储过程(Stored Procedure),是ASP程序员的必须课之一。所有的大型数据库都支持存储过程,比如Oracle、MS SQL等,(但MS Access不支持,不过,在Access里可以使用参数化的查询)。 使用存储过程有许多好处,它可以封装复杂的数据逻辑,充分发挥大型数据库本身的优势。我们知道,ASP并不适合做复杂的数据运算,而通过OLD DB访问数据库,由于数据需要在ASP和数据库之间传递,相当消耗系统资源。事实上,如果数据库仅仅起着数据存储的作用,那么它的功能是远远没有得到利用的。 关于如何创建存储过程,请参考MS SQL的相关文档。 本文介绍存储过程如何在ASP中运用。 简单的一个SQL语句: select ID,Name,Picture,Time,Duty from employ 我们可以创建一个存储过程: CREATE PROCEDURE sp_employ AS select ID,Name,Picture,Time,Duty from employ Go
而SQL语句: select ID,Name,Picture,Time,Duty from employ where ID=10230 对应的存储过程是:(用Alter替换我们已有的存储过程) ALTER PROCEDURE sp_employ @inID int AS select ID,Name,Picture,Time,Duty from employ where ID=@inID Go
下面对比一下SQL和存储过程在ASP中的情况。首先看看直接执行SQL的情况: <% dim Conn, strSQL, rs set Conn = Server.CreateObject("ADODB.Connection") Conn.Open "DSN=webData;uid=user;pwd=password" strSQL = " select ID,Name,Picture,Time,Duty from employ " Set rs = Conn.Execute(strSQL) %>
再看看如何执行Stored Procedure: <% dim Conn, strSQL, rs set Conn = Server.CreateObject("ADODB.Connection") Conn.Open "DSN=webData;uid=user;pwd=password" ’make connection strSQL = "sp_employ" Set rs = Conn.Execute(strSQL) %>
而执行带参数的Stored Procedure也是相当类似的: <% dim Conn, strSQL, rs, myInt myInt = 1 set Conn = Server.CreateObject("ADODB.Connection") Conn.Open "DSN=webData;uid=user;pwd=password" strSQL = "sp_myStoredProcedure " & myInt Set rs = Conn.Execute(strSQL) %>
你可能觉得在ASP中使用存储过程原来是这样的简单。对!就是这么简单。
转自: http://goaler.xicp.net/ShowLog.asp?ID=503 |
|
如何防止ASP木马在服务器上运行
|
来源:http://www.hackyun.com/
如果您的服务器正在受ASP木马的困扰,那么希望这篇文章能帮您解决您所面临的问题。
目前比较流行的ASP木马主要通过三种技术来进行对服务器的相关操作。
一、使用FileSystemObject组件
FileSystemObject可以对文件进行常规操作
可以通过修改注册表,将此组件改名,来防止此类木马的危害。
HKEY_CLASSES_ROOT\Scripting.FileSystemObject\ 改名为其它的名字,如:改为FileSystemObject_ChangeName
自己以后调用的时候使用这个就可以正常调用此组件了
也要将clsid值也改一下 HKEY_CLASSES_ROOT\Scripting.FileSystemObject\CLSID\项目的值
也可以将其删除,来防止此类木马的危害。
注销此组件命令:RegSrv32 /u C:\WINNT\SYSTEM\scrrun.dll
禁止Guest用户使用scrrun.dll来防止调用此组件。 使用命令:cacls C:\WINNT\system32\scrrun.dll /e /d guests
二、使用WScript.Shell组件
WScript.Shell可以调用系统内核运行DOS基本命令
可以通过修改注册表,将此组件改名,来防止此类木马的危害。
HKEY_CLASSES_ROOT\WScript.Shell\ 及 HKEY_CLASSES_ROOT\WScript.Shell.1\ 改名为其它的名字,如:改为WScript.Shell_ChangeName或WScript.Shell.1_ChangeName
自己以后调用的时候使用这个就可以正常调用此组件了
也要将clsid值也改一下 HKEY_CLASSES_ROOT\WScript.Shell\CLSID\项目的值 HKEY_CLASSES_ROOT\WScript.Shell.1\CLSID\项目的值
也可以将其删除,来防止此类木马的危害。
三、使用Shell.Application组件
Shell.Application可以调用系统内核运行DOS基本命令
可以通过修改注册表,将此组件改名,来防止此类木马的危害。
HKEY_CLASSES_ROOT\Shell.Application\ 及 HKEY_CLASSES_ROOT\Shell.Application.1\ 改名为其它的名字,如:改为Shell.Application_ChangeName或Shell.Application.1_ChangeName
自己以后调用的时候使用这个就可以正常调用此组件了
也要将clsid值也改一下 HKEY_CLASSES_ROOT\Shell.Application\CLSID\项目的值 HKEY_CLASSES_ROOT\Shell.Application\CLSID\项目的值
也可以将其删除,来防止此类木马的危害。
禁止Guest用户使用shell32.dll来防止调用此组件。 使用命令:cacls C:\WINNT\system32\shell32.dll /e /d guests
注:操作均需要重新启动WEB服务后才会生效。
四、调用Cmd.exe
禁用Guests组用户调用cmd.exe
cacls C:\WINNT\system32\Cmd.exe /e /d guests
通过以上四步的设置基本可以防范目前比较流行的几种木马,但最有效的办法还是通过综合安全设置,将服务器、程序安全都达到一定标准,才可能将安全等级设置较高,防范更多非法入侵。 |
|
MSCOMM控件的属性
|
CommPort :设置或返回端口代号。VB中有16个端口限制。
MSComm1.CommPort=1 ‘使用Com1端口
l Setting :设置初始化参数。以字符串形式设置或传回连接速度,奇偶校验,数据位,停止位等4个参数。如“9600,N,8,1”,奇为O,偶为E。
MSComm1.Setting=”9600,N,8,1”
l Input :从输入寄存器传回并移除已被读取的字符。
Buffer=MSComm1.Input ,读入Buffer字符串变量中
l Output : 写入输出寄存器
l InputLen:指定由串行端口读入的字符串长度。默认值为0,此值会使得控件的Input指令一次读取所有输入缓冲区的数据。如果我们需要对固定的字符串长度做特别的运算时,要设置该属性。
l HandShaking :指定通信两方的握手协议。握手协议要做的就是数据传输速度的控制,也称为”流量控制(Flow Control)”。简单说,如果一方送出的数据的速度超过另一方所能处理的速度,接收方便会要求传送方暂停送出数据。
RTS/CTS 握手协议是硬件握手协议,它用RTS脚位及CTS脚位的功能。
XON/XOFF 即软件握手协议。它使用XON表示暂停数据的传送;而使用XOFF表示恢复传送。其中由于XON使用chr(19)作为控制信号,若所传送的数据中含有chr(19)字符,将使得传送暂停,而发生错误。
l Rthreshold: 设置或返回接收事件的字符数。当接收寄存器达到所设置的字符数时,将会引发Oncomm事件中的接收事件。默认为0。表示无论寄存器有多少字符均不会引发接收事件。
l CommEvent:只要由通信错误或事件发生时都会产生Oncomm事件。
l DTREnable:判断在通信时是否启用Data Terminal Ready(DTR)线路。DTR是由计算机传送到调制解调器的信号,指示计算机在等待接收传输。当设为True时,DTR线会在连接端口打开时置高电位。在端口关闭时置低电位。使用者可以置低电位来挂断电话。
l RTSEnable:决定是否使Request To Send 线有效。一般情况下,由计算机传送RTS信号到调制解调器,以请示准许传送数据。True为高电位。
l InBufferCount:传回在接收寄存器中的字符数。设0,以清空接收寄存器。
l InputMode:取出接收寄存器数据的形式。(字符串或二进制形式),对于数据中只用ANSI字符集,则使用字符串形式。ComInputModeText。有控制字符Nulls或含有ASCII128以上的字符,使用comInputMode Binary.
l DSRHolding:传回DSR脚位状态。高为True,低为False。
l CTSHolding:传回通信端口的CTS脚位状态
l CDHolding:传回通信端口的DCD脚位状态。 |
|
最佳ASP.NET编程习惯
|
初学编程的朋友往往喜欢收集一些很“奇妙”的编程技巧,然而,技巧的积累往往并没有提高程序质量,反而引导一些编程者一味追求奇和新,忘记了基本编程习惯的培养,不利于团队的合作,可能,这也是中国并不缺少聪明的程序员,但是缺少聪明的开发团队的一个原因吧。在ASP.NET的开发中,可以学习的技巧不少,但是,一些基本的编程习惯我们一定要养成,这样不但能根本上提高程序质量和开发效率,而且,也利于程序的阅读和团队开发。如果自己写的程序只有自己可以看懂或者只有几个人可以看懂,即使程序技巧神乎其技,对于程序的升级和维护都是致命问题。
一、 错误(以外)的处理 程序健壮性最基本要求就是程序错误的处理与捕捉,在ASP.NET中,错误的处理有和其他编程语言一样的机制,可以使用Try…Catch…Finally等方式,这一点和ASP相比具有较大的进步。而且,使用这些错误处理方法,可以大大提高程序的可读性和程序调试速度,在这几个优势结合的情况下,我们更加应该注意这一点。 关于错误的处理,我们可以参考这篇文章(英文): http://www.123aspx.com/redir.aspx?res=28336
二、 字符串的处理 网页设计中,字符串的处理几乎是最常见的了。使用ASP.NET以后,字符串的处理比ASP的速度快,而且,在ASP.NET中,专门增加一个字符串处理类StringBulider,使用这个类可以完成一些常见的字符串操作,而最主要的,使用StringBuilder可以大大提高字符串处理速度。 在ASP.NET中,最常见的就是使用“&”来连接两个字符串: Dim myOutputString As String = "My name is" Dim myInputString As String = " Alex" myOutputString = myOutputString & myInputString Response.Write(myoutputString) 现在,我们来看看StringBuilder的使用,在使用StringBuilder的时候,我们对字符串可以做一些基本的操作,比如Append、Replace、Insert、Remove等,现在我们来看具体举例。 (1)StringBuilder中Append的使用 Append和其他语言的Append一样,就是在字符串最后增加其他字符。 Dim sb as StringBuilder = New StringBuilder() sb.append( "<table border='1' width='80%'>" ) For i = 0 To RowCount - 1 sb.Append("<tr>") For k = 0 To ColCount - 1 sb.Append("<td>") sb.Append( dt.Rows(i).Item(k, DataRowVersion.Current).toString()) sb.Append( "</td>" ) Next sb.Append("<tr>") Next sb.Append( "</table>") Dim strOutput as String = sb.ToString() lblCompany.Text = strOutput 在以上的程序中,用Append方法实现了一个表格的输出,需要注意的一点是,StringBulider必须首先使用ToString()方法将其转化为String类型才可以直接输出。在以上的举例中,我们看到的全部是Append一个直接的字符串,其实,这个方法有一个很方便的功能,那就是可以直接Append其他类型的变量,比如可以直接Appemd一个Integer类型的数值,当然,我们输出以后自动转化为一个字符串: Sub Page_Load(Source As Object, E As EventArgs) Dim sb As System.Text.StringBuilder Dim varother As Integer varother=9999 sb =new System.Text.StringBuilder() sb.append("<font color='blue'>可以Append其他类型:</font>") sb.append(varother) Response.write(sb.toString()) End Sub (2)字符串中其他方法的使用 我们还可以使用其他方法,我们来看看常见的: Insert方法,可以在指定位置插入其他字符,使用方法:Insert(插入位置,插入字符); Remove方法,可以在指定位置删除指定字数字符,使用方法:Remove(其实位置,字符数); Replace方法,可以替换指定字符,使用方法:replace(被替换字符串,替换字符串) 字符串的具体介绍和使用方法可以参考以下文章(英文): http://aspfree.com/aspnet/stringbuilder.aspx http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemTextStringBuilderClassTopic.asp
三、 数据库链接Connection和DataReader的关闭 在使用ASP编程的时候,我们就已经知道,在使用数据库连接以后,一定要将连接关闭,然后设置为NoThing。在Asp.NET中,我们仍然需要这样使用,不过,在ASP.NET中,由于使用了ADO.NET,所以,在一些相关的处理方面,实际还是有一些细微的区别,而这些区别,往往也就是我们设计的时候最需要注意的。现在,我们通过举例,来看看在常见的ADO.NET操作中,需要注意哪些问题。 (1)举例一 Dim myConnection As SqlConnection = new SqlConnection(ConfigurationSettings.AppSettings("DSN_pubs")) Dim myCommand As SqlCommand = new SqlCommand("Select pub_id, pub_name From publishers", myConnection) Dim myDataReader As SqlDataReader Try myConnection.Open() myDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection) DropDownList1.DataSource = myDataReader DropDownList1.DataBind() Catch myException As Exception Response.Write("An error has occurred: " & myException.ToString()) Finally If Not myDataReader Is Nothing Then '关闭DataReader myDataReader.Close() End If End Try 在以上的举例中,我们注意到,这里只关闭了DataReader,并没有关闭Connection。为什么呢?仔细观察以上的ExecuteReader方法,原来,设置了ExecuteReader参数,当执行完ExecuteReader以后,会自动关闭Connection。所以,这样设置以后,就没有必要再手动关闭Connection了。 (2)举例二 Dim myConnection As SqlConnection = new SqlConnection(ConfigurationSettings.AppSettings("DSN_pubs")) Dim myCommand As SqlCommand = new SqlCommand("Select pub_id, pub_name From publishers", myConnection) Try myConnection.Open() DropDownList1.DataSource = myCommand.ExecuteReader() DropDownList1.DataBind() Catch myException As Exception Response.Write("An error has occurred: " & myException.ToString()) Finally If Not myConnection Is Nothing AndAlso ((myConnection.State And ConnectionState.Open) = ConnectionState.Open) Then myConnection.Close() End If End Try 在以上的举例中,我们发现,居然没有关闭DataReader。为什么呢?其实上面的代码中,没有直接生成DataReader对象,当然也就无从关闭了。需要注意一点的是,在关闭Connection之前,程序首先判断Connection是否已经打开,如果没有打开,也就没必要关闭了。
四、使用Web.Config/Maching.Config保存常用数据 一些数据我们需要时常使用,比如使用ADO.NET的时候,最常见的就是数据库连接语句,在ASP中,我们常常将这些信息保存在Application中。当然,在ASP.NET中,也可以这样,不过,ASP.NET已经提供一个配置文件WEB.Config,所以,我们最好将这些信息保存在WEB.Config中,当然,我们也可以保存在Machine.Config中,不过,这样的话,整个网站都必须使用,所以,一般我们都使用Web.Config。现在,我们来看具体这个文件的使用。 (1)Web.Config文件的设置 首先,我们来看Web.Config的设置,我们在这个文件中增加设置以下两个项目,设置如下: <configuration> <appsettings> <add key="dsn" value="myserver"/> <add key="someotherkey" value="somevalue"/> </appsettings> </configuration> (2)变量的使用 以上XML文件设置了dsn和someotherkey两个变量,现在我们看看程序中怎样使用: <html> <script language="VB" runat=server> Sub Page_Load(Sender as Object, E as EventArgs) Dim AppSettings as Hashtable = Context.GetConfig("appsettings") DSN.Text = AppSettings("dsn") SomeOther.Text = AppSettings("someotherkey") End Sub </script> <body> DSN Setting: <asp:label id="DSN" runat=server/> <br> Some Other Setting: <asp:label id="SomeOther" runat=server/> </body> </html> 上面的程序我们看到,使用这样定义的变量很简单也很方便。
五、使用.NET的方式调试程序 ASP程序的调试一直是编写ASP最难的地方,这一点,ASP程序员大概都深有体会,因为大家都是使用Response.write来调试。而这样调试最大的缺点是,当我们调试完毕,必须一个个来删除或者注释掉这些信息,想一想,如果程序代码达到几百行或者页面很多的程序,这样的工作是多么枯燥,最怕一点,忘记将这些调试用的write删除,可能在用户使用的时候就会出现一些不雅的调试信息。 使用ASP.NET以后,我们可以直接定义Trace来实现程序的调试。以上提到的麻烦可以轻松解决,熟悉,Trace可以通过具体页面和在Web.Config配置文件中来定义实现,这样,当程序调试完毕以后,直接将Trace设置为Off就可以了,这样,程序就不会有调试功能了。 (1)页面调试的实现 在一个具体的页面需要实现调试功能的时候,我们可以这样设置: <%@ Page Language="VB" Trace="True" %> (2)定义WEB.Config实现 在WEB.CONFIG中,我们也可以实现程序调试的打开: <configuration> <system.web> <trace enabled="true" requestLimit="10" localOnly="false"/> </system.web> </configuration> 使用以上的设置打开Trace以后,我们在具体的程序中就可以使用Trace来调试程序了,比如: Trace.Write("This is some custom debugging information") 或者调试程序变量: Trace.Write("This is is my variable and it's value is:" & myVariable.ToString()) 以上设置我们可以看出,在ASP.NET中,程序调试功能已经很方便简单了,我们在程序设计中如果忽略这些特点,继续采用ASP的思维来设计程序,那么我们的程序不但效率没有提高,也增加了其他开发者合作的难度。
六、总结 以上的一些程序编写习惯,我们可以慢慢养成,在程序设计的时候,不要太在意程序是否最简洁灵活,对于一般开发者而言,程序规范化和可读性可能比追求程序的灵活性更加重要。在互联网资源越来越丰富的情况下,我们可以参考一些很规范的程序源代码来学习,当然,最好的莫过于微软自己的东西,我们可以参考以下网址:http://www.asp.net,关于更多的程序编写问题,我们可以参考以下网址: http://www.gotdotnet.com/team/asp/ASP.NET%20Performance%20Tips%20and%20Tricks.aspx |
|
Flash 组件应用与开发2
|
Flash 组件应用与开发(下)
Flash V2组件开发
在Flash MX Professional 2004中,开发人员开可以在项目中自己创建新的V2组件。在开始开发V2组件之前,首先要了解MovieClip类、UIObject类和UIComponent类,因为它们是Flash V2组件的基类,所有Flash自带的组件都是它们的直接或间接子类。开发一个组件可以从原先的父类继承,扩展现有的组件类,使被创建的组件在父类的基础上进一步扩展。另外,也可以创建一个不带父类的组件,以实现一些其它的功能。在这里将重点讨论如何扩展现有的组件类。扩展一个现有组件类,通常包括以下几个步骤:
1、组件首先作为一个电影剪辑(MovieClip)被创建,在该电影剪辑中创建两个图层,分别用于组件界面元素和脚本。然后在库的下拉菜单中选择Component Defination,在该对话框中的AS2.0 Class中输入该组件所要关联的类的完全限定名。当界面元素定义完成以后,就可以在外部文件中创建组件的属性、事件和方法,当然,组件的界面元素也可以在类中使用代码动态创建。
2、在定义组件类文件时,首先必须导入所需要的类,前面已经说过,MovieClip类、UIObject类和UIComponent类是V2组件的基类,所以如果当前创建的组件是从V2组件的任意组件扩展,那么就必须了解这三个基类,和其下的相关组件类。关于组件的特性可以查看Macromedia公司发布的组件字典,也可以直接在FlashInstalDir\en\First Run\Classes目录查看类文件代码。
3、确定组件所要扩展的类以后,就要为组件类编写构造函数(Constructor)。一般情况下,构造函数建议为空,这样才能用对象的属性接口来定义对象属性。此外,根据初始化调用顺序的不同,有时在构造函数中设置属性会导致覆盖默认值。
4、接下来要做的是添加组件的版本信息,如果当前开发的组件是作为组件包的一部分,那么可以把版本信息放到另外一个外部文件中。在定义版本信息时,可以继承UIObject类的静态字符串属性version。另外还需要定义三个比较重要的属性:symbolName,symbolOwner和className;他们都是从组件基类继承的。symbolName定义为静态的字符串变量,用于指定组件符号的名称;symbolOwner定义为静态的Object类型,是该类的一个完全限定名,它将在createClassObject() 方法的内部调用中被使用;className定义了组件类名称。
5、当这些都完成以后,就要开始定义组件功能相关的属性和方法。在属性和方法定义时,比较好的做法是确定每一个属性和方法的访问特性,使组件为用户提供一个良好的应用程序接口(API)。所以在定义属性和方法时要使用private和public来声明属性的可访问性,并使用setter和getter函数来设置和获取属性的值。这样就更好的地实现了组件的封装,使用户无须了解组件的内部细节。
所有组件必须实现两个核心方法:始化方法和大小调整。如果不在自定义组件的类文件中覆盖两个方法,Flash Player 可能会产生错误。Flash 在创建类时调用初始化方法。初始化方法应该调用父类的初始化方法,因为只有在调用此方法之后,才能正确设置width、height 和和其它的影片剪辑参数。
function init(Void):Void
{
// 调用父类的初始化方法
super.init();
//在这里添加与本组件相关的初始化代码
}
大小调整的方法也与初始化方法类似:
function size(Void):Void
{
super.size();
//在这里添加与本组件相关的大小调整代码
}
6、为了让属性在开发面板中可见,还必须为属性声明相关的元数据(Metadata)。元数据标记可以定义组件属性、数据绑定属性和事件。Flash 可以解释这些语句并相应地更新开发环境。元数据与类声明或单个的数据字段相关。元数据语句绑定到脚本的下一行。例如,在定义组件属性时,在属性声明的前一行添加元数据标记。在定义组件事件时,在类定义之外添加元数据标记,以便将事件绑定到整个类。对属性而言,有两个比较重要的元数据:Inspectable和InspectableList。
Inspectable元数据定义了在“组件检查器(Component Inspector)”面板中向用户显示的组件的属性。语法如下:
[Inspectable( value_type=value [,attribute=value,...] ) ]
property_declaration name:type;
Inspectable元数据还包括若干元数据标记:
·name:类型为String(可选),属性在开发面板中的显示名称。
·type:类型为String(可选)指定属性的类型。如果省略,则使用属性的类型。以下下是可接受的值: Array、 Object、List、String、Number、Boolean、Font Name、Color。
·defaultValue:类型可以是String或Number(必需)。指定属性的默认值。
·enumeration:类型为String(可选)。指定以逗号分隔的属性合法值列表。
·category:类型为String(可选)。将属性划分到属性检查器中的某个特定子类别中。
InspectableList 元数据关键字用于确切地指定属性检查器中应显示可检查参数的哪个子集。可以将 InspectableList 与 Inspectable 组合使用,这样即可隐藏子类组件的继承属性。如果不给组件的类添加 InspectableList 元数据关键字,所有可检查的参数(包括组件父类的可检查参数)都会显示在属性检查器中。其的语法如下:
[InspectableList("attribute1"[,...])]
// class definition
InspectableList 关键字必须紧挨着类定义且在它之前,因为它应用于整个类。
7、定义组件的事件,首先要使用Event元数据关键字声明事件。Event 元数据关键字用于定义组件事件。其语法如下:
[Event("event_name")]
在类文件中必须把 Event 语句添加到类定义之外,以便将它们绑定到类,而不绑定到类的特定成员。首先组件类会继承基类事件。如果当前定义组件的基类是UIComponent,那么该组件中已经包括了MovieClip类、UIObject类和UIComponent类的28个事件。但事实上,这28个事件并不是都可以用的。其原因很简单,因为组件可以有它的组成结构,组件内部可能还有组件或是其它的元件实例。组件要为用户提供一个统一的接口,就必须抽取其内部结构的某些事件并把它们定义为组件的事件,这是一种基于组件内部组成结构的事件。比如说组件包括两个文本框T1和T2,这时可以根据组件的功能要求把T1的change事件发布为组件的PP事件,而把T2的change事件发布为组件的UU事件,当然关于组件事件的名称可以由组件开发人员自己定义。
那么究竟如何为组件定义一个新的事件呢?对于上面的那个例子,可以做如下定义:
//导入类
import mx.core.UIComponent;
//用元数据声明组件事件
[Event("PP")]
[Event("UU")]
//指明该类从UIComponent继承
class T_T extends UIComponent
{
//在编辑环境中已经创建两个输入文本(Input Text),并在类中声名其引用。
var T1:TextField;
var T2:TextField;
//定义构造函数
function T_T()
{
//在构造函数中发布T1的change事件
T1.onChanged=function()
{ //创建一个事件对象,存放与事件相关的信息
var eventObj = new Object();
//定义事件类型的名称
eventObj.type = "PP";
//指明事件广播(发生)的对象
eventObj.target = _parent;
//把事件作为组件的事件发布
_parent.dispatchEvent(eventObj);
}
//在构造函数中发布T2的change事件
T2.onChanged=function()
{
var eventObj = new Object();
eventObj.type = "UU";
eventObj.target =_parent;
_parent.dispatchEvent(eventObj);
}
}
}
在以上代码中,先用元数据声明了组件的两个事件UU和PP,然后又在组件类的构造函数中定义T1和T2的change事件,并在它们的change事件中用_parent.dispatchEvent(eventObj);语句把chang事件发布为组件事件。dispatchEvent()方法需要一个Object类型的事件对象作为参数,该对象中保存了与事件相关的信息:target指明事件广播(发生)的对象;type定义了事件类型的名称——也可以认为是事件名称。在事件脚本中使用如下代码就可以对事件做出响应,其使用方法与一般的事件处理方法一致:
//对组件的PP事件做出响应
on(PP)
{ trace("PP"); }
//对组件的UU事件做出响应
on(UU)
{ trace("UU"); }
组件的属性的改变也可以作为事件发布,例如:
private var Tm:String;
//在setter中发布组件的事件
public function set TTm(val:String)
{
Tm=val;
var eventObj = new Object();
eventObj.type = "KK";
eventObj.target =this;
this.dispatchEvent(eventObj);
}
当然,还要用Event元数据为组件声明事件。但事实上,没有Event元数据声明的事件组件同样可做出响应。Event元数据声明似乎仅仅是多了一个代码提示而已。所以元数据只是为组件提供了一个更加友好的用户接口,使开发人员更加容易得使用组件。
在发布组件之前,还可以为组定制一个图标。图标大小要求为 18 x 18 像素,并保存为 PNG 格式。它的 Alpha 透明度必须是8位,左上角的像素要求是透明的,以支持遮罩。另外还需要在组件类文件中定义添加元数据声明:
[IconFile("component_name.png")]
该声明和事件声明一样,必须放在类定义之前,使该声明作用到组件类。最后将该图像保存到到FLA文件所在的同一目录中。在导出 SWC 文件时,Flash将在自动包含该图像。
当组件定义完整,测试通过后,就可以发布组件供其他开发人员使用。Flash MX 2004 将组件导出为组件包(SWC 文件)。在发布组件时,只需向其他开发者提供 SWC文件就可以了。此文件包含与组件相关的所有代码、SWF 文件、图像和元数据,因此其他开发者可以方便地将它放到自己的 Flash开发环境中。
这里对Flash V2组件开发做了初步的讨论。在具体的开发时,应根据组件的功能特性非常细致地刻画组件的属性、事件和方法,声明元数据定义良好的用户接口。如果该组件是一个可视的组件还需要为组件制作组件界面的图形元素。 |
|
Flash 组件应用与开发1
|
Flash 组件应用与开发
一、Flash 组件概述
组件是带有参数的电影剪辑,这些参数可以用来修改组件的外观和行为。每个组件都有预定义的参数,并且它们可以被设置。每个组件还有一组属于自己的方法、属性和事件,它们被称为应用程序程接口(Application Programming Interface,API)。使用组件,可以使程序设计与软件界面设计分离,提高代码的可复用性。Flash MX 2004 或 Flash MX Professional 2004 中包含的组件不是 FLA 文件,而是 SWC 文件。SWC 是用于组件的 Macromedia 文件格式。库项目中的电影剪辑可以被预编译成swf文件。这样可以缩短影片测试和发布的执行时间。将 SWC 文件拷贝到 First Run\Components目录后,该组件便会出现在“组件”面板中。
二、组件基类
Flash 自带的组件都位于mx.controls包中。组件直接或间接继承于UIComponent类,UIComponent类对UIObject类做了扩展,而UIObject类又是MovieClip类的子类。MovieClip类不属于任何包,定义文件位于FlashInstalDir\en\First Run\Classes目录。UIComponent类和UIObject类都位于mx.core包中,定义文件位于FlashInstalDir\en\First Run\Classes\mx\core目录。
UIObject类对MovieClip类进行封装,所有Flash V2组件都可以共享它的方法、属性和事件。UIObject类使组件在样式、事件和缩放比例调整上得到了实现。它提供了动态创建删除组件的方法:
·createObject方法:直接调用attachMovie函数,返回一个MovieClip类型的引用。
·createClassObject方法:调用createObject方法,创建一个指定类的组件实例,并返回所创建的组件的引用。
·createEmptyObject方法:创建一个空的UIObject实例。
·destroyObject方法:使用delete语句删除已经创建的组件实例。
UIObject还封装了其它的一些方法,包括:
·redraw方法:在当前帧重新绘制组件。
·invalidate方法:标记组件,使之在下一个帧间隔重新绘制。
·move方法:把组件移动到指定位置。
·setSize方法:设置组件大小。
·setSkin方法:设置组件皮肤。
·getStyle方法:获取样式信息。
UIObject类的属性除了scaleX和scaleY外,其它都是只读属性,使用时需要注意。所以如果要在运行时调整组件外观,就必须使用UIObject类的方法。对于只读属性的赋值是无效的,即使是对非只读属性的赋值,有时也会造成组件在外观显示上的差错。UIObject类还定义了一系列的事件,包括加载事件(load)、卸载事件(unload)、移动事件(move)、重绘事件(draw)和大小调整事件(resize)。
利用UIObject类的组件创建方法,可以在运行时创建组件实例。
UIComponent类从UIObject类继承,它并不是一个可视的组件。和UIObject类一样,所有Flash V2组件都可以共享它的方法和属性。它实现了组件的焦点获取、键盘输入,组件的禁用和启用以及组件的按布局调整自动大小。
UIComponent类的主要方法有:
·getFocus方法:利用焦点管理器(Selection)返回一个当前获取焦点的对象的引用。
·setFocus方法:使组件获取焦点。
UIComponent类的enabled属性指定组件实例是否可用;tabIndex属性指定组件的焦点获取顺序。UIComponent类还定义一系列焦点和键盘事件:焦点获取事件(focusIn),焦点转移事件(focusOut)、键盘按下事件(keyDown)和键盘释放事件(keyUp)。
三、Flash V2 组件的基本使用方法
在Flash MX 2004和 Flash MX Professional 2004自带了一套组件称为Flash V2组件,它是从Flash MX的V1组件升级而来的,V1组件和V2组件尽量不要一起使用以免发生一些错误。V2组件支持实时预览,使开发者在编辑状态下就能看到组件的外观效果。开发者可以自行设置是否需要实时预览和实时预览的模式,以节省计算机资源。在ControlàEnable Live Preview菜单设置是否使用实时预览,在ViewàPriview Mode菜单选择预览模式。组件实质上是一些被编译好的电影剪辑,其格式为SWC。SWC文件类似与Zip文件,可以使用一般的解压缩程序进行解压查看其内容。电影剪辑可以在编辑环境中直接发布为组件,也可以直接编译存储为swc格式的组件文件,便于其他开发者使用。同样,开发者也可以从外部导入组件。
使用组件,必须把组件面板中所需要的组件拖到舞台(Stage),使组件出现在库面板。这样组件就可以象普通的库项目一样被使用。使用脚本可以动态的创建组件实例,运行时创建组件可以有三个方法:createObject()、creatClassObject()和attachMovie()。attachMovie()是MovieClip类的方法,createObject()和creatClassObject()是UIObject类方法,但事实上它们都是对attachMovie()的直接或间接调用。
组件被添加后可以在属性或参数面板中直接设置组件的参数。另外还要为组件定义事件,最简单的方法是使用on(eventName)进行定义。另外还可以使用侦听器和事件处理函数等定义组件事件的处理方法。组件的事件定义比较灵活,使用何种方式定义取决与个人的习惯与偏好。当事件发生时,组件会广播一个Object类型的事件参数,该参数中包括了事件发生对象和事件类型的信息。另外,使用深度管理器(DepthManager)可以对组件进行深度管理。
Flash组件最大的特点是开发者可以自定义组件,尤其是界面元素的自定义,使其更具有吸引力。V2组件有它自己的一套默认界面方案,称为主题(Theme)。主题包括两个方面:样式(Style)和外观(Skin)。UIObject类的setStyle()和getStyle()方法可以获取和设置组件的样式。样式的设置比较简单,主要有以下三种方式:
·直接设置属性:
T.color=0xff5567;
·使用简单的setStyle()名值对方法自定义样式:
instanceName.setStyle("property", value);
·把样式对象与setStyle()方法结合使用来自定义样式:
//创建一个样式对象
var styleObj = new mx.styles.CSSStyleDeclaration;
//刻画样式细节
//……
styleObj.fontSize = 18;
//把样式应用到组件实例
b.setStyle("styleName", styleObj);
样式的级别包括4个层次:全局样式,应用于所有组件;组件类单独的默认样式,应用于某一类的组件;自定义样式;直接设置组件实例的属性。对于不同级别的样式Flash按照一定的顺序分别把这些样式应用到组件。
首先,Flash 查找组件实例上的样式属性,如果实例上没有直接设置样式,Flash 将查看实例的styleName 属性,确定是否向它分配了样式声明。如果 styleName 属性没有被分配样式声明,Flash 将查找默认类样式声明上的属性。如果没有类样式声明,并且属性没有继承它的值,则将检查 _global 样式声明。如果属性未在 _global 样式声明中定义,则该属性为 undefined。
另外,如果没有类样式声明,但属性确实继承了它的值,Flash 将查找该实例父级上的属性。如果属性未在父实例上定义,Flash 将检查父实例的 styleName 属性;如果未定义该属性,Flash 将继续查看父实例,直到 _global 级别。如果属性未在 _global 样式声明中定义,则该属性为undefined。
另一方面,为了更好的使用组件,还需要修改或重新定义组件外观。Flash V2的外观定义文件位于FlashInstralDir\en\First Run\ComponentFLA文件夹下。在修改外观时,需要把原始的外观定义文件作为外部库导入(FileàOpen External Library),并把外部库中的外观定义库项目拖到当前文档的库中,外观库项目通常都是电影剪辑(MovieClip)。每一个组件外观定义库项目文件夹中都包含一个States文件夹,其中定义了组件在不同状态下的外观,每一个状态都指定了一个链接名(linkageName)作为脚本引用,如果修改了这个名称,则会使组件在该状态下的外观加载发生错误。在组件的类文件中,每一个状态都使用一个字符串属性指定其外观库项目的链接名,如果要重新定义组件某一状态下的外观,只要在脚本中修改这个字符串属性的值就可以了,当然首先必须存在可链的新的外观库项目。
了解了这样一个组件外观机制以后,组件外观的修改就变的非常简单。其关键就是修改或重新定义一组新的外观库项目并指定其链接名,然后修改组件类文件中指定组件外观的属性。开发者可以在组件实例的初始化事件(initialize)中修改组件实例的外观。修组件所有实例外观的方法比较多,例如_root的第一帧使用ClassName. prototype.stateName=value语句,该语句也可以直接在#initclip和#endinitclip代码块中使用;另外还可以使用类继承的方式,在组件初始化时就为组件外观链接属性指定新的值,这里也需要用到#initclip、#endinitclip代码块。#initclip和#endinitclip是Flash的编译器命令,作为初始化代码块的开始标记和结束标记。只要符号(symbol)被定义,那么初始化代码就被先于第一帧执行,而且紧执行一次。所以在这个代码块中,可以为整个组件类指定不同状态下的外观 |
|
javascript实现随机产生数字与字母的组合
|
1。
<script language="JavaScript" type="text/JavaScript"> //str_0 长度 //str_1 是否大写字母 //str_2 是否小写字母 //str_3 是否数字 function rnd_str(str_0,str_1,str_2,str_3) { var Seed_array=new Array(); var seedary; var i;
Seed_array[0]="" Seed_array[1]= "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"; Seed_array[2]= "a b c d e f g h i j k l m n o p q r s t u v w x y z"; Seed_array[3]= "0 1 2 3 4 5 6 7 8 9";
if (!str_1&&!str_2&&!str_3){str_1=true;str_2=true;str_3=true;}
if (str_1){Seed_array[0]+=Seed_array[1];} if (str_2){Seed_array[0]+=" "+Seed_array[2];} if (str_3){Seed_array[0]+=" "+Seed_array[3];}
Seed_array[0]= Seed_array[0].split(" "); seedary="" for (i=0;i<str_0;i++) { seedary+=Seed_array[0][Math.round(Math.random( )*(Seed_array[0].length-1))] } return(seedary);
}
var tmp=rnd_str(6,true,true,true); document.write(tmp); </script>
2。
可选定长度的随机字母数字生成器:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE> New Document </TITLE> <META http-equiv=Content-Type content="text/html; charset=gb2312"> <META NAME="Author" CONTENT="Seagle.K"> <STYLE TYPE="text/css">
</STYLE> <SCRIPT LANGUAGE="JavaScript"> function getrandom(len) { var seed = new Array( 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', '0123456789' ); var idx,i; var result = ''; for (i=0; i<len; i++) { idx = Math.floor(Math.random()*3); result += seed[idx].substr(Math.floor(Math.random()*(seed[idx].length)), 1); }
return result; } </SCRIPT> </HEAD> <BODY> 长度: <SELECT id="sel"> <option value=1>1</option> <option value=3>3</option> <option value=5 selected>5</option> <option value=7>7</option> <option value=9>9</option> </SELECT> <BR> 生成: <INPUT TYPE="text" id="txt"> <INPUT TYPE="button" VALUE=" GO " ONCLICK="txt.value=getrandom(sel.value)"> </BODY> </HTML> |
|
ASP.NET 2.0里轻松获取数据库连接统计数据
|
ASP.NET 2.0中的SqlConnection多了一个StatisticsEnabled属性和ResetStatistics()、RetrieveStatistics()两个方法,用于获取SQLServer的连接统计数据。
<%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <%@ page language="C#" %> <script runat="server"> void Page_Load(object sender, EventArgs e) { string connString = "Northwind的连接串"; SqlConnection conn = new SqlConnection(connString); conn.StatisticsEnabled = true; conn.ResetStatistics(); conn.Open(); SqlCommand cmd = new SqlCommand("SELECT * FROM Orders", conn); SqlDataReader reader = cmd.ExecuteReader(); reader.Close(); conn.Close();
Hashtable ht = (Hashtable)conn.RetrieveStatistics(); foreach (string key in ht.Keys) { Label1.Text += "Key: " + key + " = " + ht[key] + "<BR />"; } } </script> <html> <head id="Head1" runat="server"> <title>Untitled Page</title> </head> <body> <form id="Form1" runat="server" autocomplete="on"> <asp:Label ID="Label1" Runat="server" Text=""></asp:Label> </form> </body> </html>
运行后的结果就是SQLServer连接统计数据结果:
Key: NetworkServerTime = 0 Key: BytesReceived = 156913 Key: UnpreparedExecs = 1 Key: SumResultSets = 1 Key: SelectCount = 1 Key: PreparedExecs = 0 Key: ConnectionTime = 30 Key: ExecutionTime = 30 Key: Prepares = 0 Key: BuffersSent = 1 Key: SelectRows = 830 Key: ServerRoundtrips = 1 Key: CursorOpens = 0 Key: Transactions = 0 Key: BytesSent = 48 Key: BuffersReceived = 20 Key: IduRows = 0 Key: IduCount = 0 |
|
Asp.NET常用函数 (VB.net)
|
作者: love610 加入时间: 2004-09-21 文档类型: 来自: 浏览统计: total: 100 year: 100 quarter: 100 month: 100 week: 62 today: 8
Asp.NET常用函数 (新手必读!)
Ucase(string) 将字符串转换为大写。 Val(string) 将代表数字的字符串转换为数值型态,若字符串中含有非数字的内容则会将其去除后,合并为一数字。 Weekday(date) 取的参数中的日期是一个星期的第几天,星期天为1、星期一为2、星期二为3 依此类推。 WeekDayName(number) 依接收的参数取得星期的名称,可接收的参数为1 到7,星期天为1、星期一为2、星期二为3 依此类推。 Split(expression[, delimiter]) 以delimiter 参数设定的条件字符串来将字符串分割为字符串数组。 Sqrt(number) 取得一数值得平方根。 Str(number) 将数字转为字符串后传回。 StrReverse(expression) 取得字符串内容反转后的结果。 Tan(number) 取得某个角度的正切值。 TimeOfDay() 取得目前不包含日期的时间。 Timer() 取得由0:00 到目前时间的秒数,型态为Double。 TimeSerial(hour, minute, second) 将接收的参数合并为一个只有时间Date 型态的数据。 Timavalue(time) 取得符合国别设定样式的时间值。 Today() 取得今天不包含时间的日期。 Trim(string) 去掉字符串开头和结尾的空白。 TypeName(varname) 取得变量或对象的型态。 Ubound(arrayname[, dimension]) 取得数组的最终索引值,dimension 参数是指定取得第几维度的最终索引值。 MonthName(month) 依接收的月份数值取得该月份的完整写法。 Now() 取得目前的日期和时间。 Oct(number) 将数值参数转换为8 进制值。 Replace(expression, find, replace) 将字符串中find 参数指定的字符串转换为replace 参数指定的字符串。 Right(string,length) 由字符串右边开始取得length 参数设定长度的字符。 RmDir(path) 移除一个空的目录。 Rnd() 取得介于0 到1 之间的小数,如果每次都要取得不同的值,使用前需加上Randomize 叙述。 Rtrim(string) 去掉字符串的右边空白部分。 Second(time) 取得时间内容的秒部分,型态为Integer。 Sign(number) 取得数值内容是正数或负数,正数传回1,负数传回-1,0 传回0。 Sin(number) 取得一个角度的正弦值。 Space(number) 取得number 参数设定的空白字符串。 IsDate(expression) 判断表达式内容是否为DateTime 型态,若是则传回True,反之则为False。 IsDbNull(expression) 判断表达式内容是否为Null,若是则传回True,反之则为False。 IsNumeric(expression) 判断表达式内容是否为数值型态,若是则传回True,反之则为False。 Join(sourcearray[, delimiter]) 将字符串数组合并唯一个字符串,delimiter 参数是设定在各个元素间加入新的字符串。 Lcase(string) 将字符串转换为小写字体。 Left(string, length) 由字符串左边开始取得length 参数设定长度的字符。 Len(string) 取得字符串的长度。 Log(number) 取得数值的自然对数。 Ltrim(string) 去掉字符串的左边空白部分。 Mid(string, start[, length]) 取出字符串中strat 参数设定的字符后length 长度的字符串,若length 参数没有设定,则取回start 以后全部的字符。 Minute(time) 取得时间内容的分部分,型态为Integer。 MkDir(path) 建立一个新的目录。 Month(date) 取得日期的月部分,型态为Integer。 FormatDateTime(date[,namedformat]) 传回格式化的日期或时间数据。 FormatNumber(expression[,numdigitsafterdecimal [,includeleadingdigit]]) 传回格式化 的数值数据。Numdigitsafterdecimal 参数为小数字数,includeleadingdigit 参数为当整数为0 时是否补至整数字数。 FormatPercent(expression[,numdigitsafterdecimal [,includeleadingdigit]]) 传回转换为百分比格式的数值数据。numdigitsafterdecimal 参数为小数字数,includeleadingdigit 参数为当整数为0 时是否补至整数字数。 GetAttr(filename) 传回档案或目录的属性值。 Hex(number) 将数值参数转换为16 进制值。 Hour(time) 传回时间的小时字段,型态是Integer。 Iif(expression, truepart, falsepart) 当表达式的传回值为True 时执行truepart 字段的程序,反之则执行falsepart 字段。 InStr([start, ]string1, string2) 搜寻string2 参数设定的字符出现在字符串的第几个字符,start 为由第几个字符开始寻找,string1 为欲搜寻的字符串,string2 为欲搜寻的字符。 Int(number) 传回小于或等于接收参数的最大整数值。 IsArray(varname) 判断一个变量是否为数组型态,若为数组则传回True,反之则为False。 Day(datetime) 依接收的日期参数传回日。 Eof(filenumber) 当抵达一个被开启的档案结尾时会传回True。 Exp(number) 依接收的参数传回e 的次方值。 FileDateTime(pathname) 传回档案建立时的日期、时间。 FileLen(pathname) 传回档案的长度,单位是Byte。 Filter(sourcearray, match[, include[, compare]]) 搜寻字符串数组中的指定字符串,凡是数组元素中含有指定字符串,会将它们结合成新的字符串数组并传回。若是要传回不含指定字符串的数组元素,则include 参数设为False。compare 参数则是设定搜寻时是否区分大小写,此时只要给TextCompare 常数或1 即可。 Fix(number) 去掉参数的小数部分并传回。 Format(expression[, style[, firstdayofweek[, firstweekofyear]]]) 将日期、时间和数值资料转为每个国家都可以接受的格式。 FormatCurrency(expression[,numdigitsafterdecimal [,includeleadingdigit]]) 将数值输出为金额型态。 numdigitsafterdecimal 参数为小数字数,includeleadingdigit 参数为当整数为0 时是否补至整数字数。 CObj(expression) 转换表达式为Object 型态。 CShort(expression) 转换表达式为Short 型态。 CSng(expression) 转换表达式为Single 型态。 CStr(expression) 转换表达式为String 型态。 Choose (index, choice-1[, choice-2, ... [, choice-n]]) 以索引值来选择并传回所设定的参数。 Chr(charcode) 以ASCII 码来取得字符内容。 Close(filenumberlist) 结束使用Open 开启的档案。 Cos(number) 取得一个角度的余弦值。 Ctype(expression, typename) 转换表达式的型态。 DateAdd(dateinterval, number, datetime) 对日期或时间作加减。 DateDiff(dateinterval, date1, date2) 计算两个日期或时间间的差值。 DatePart (dateinterval, date) 依接收的日期或时间参数传回年、月、日或时间。 DateSerial(year, month, day) 将接收的参数合并为一个只有日期的Date 型态的数据。 Datevalue(datetime) 取得符合国别设定样式的日期值,并包含时间。 Abs(number) 取得数值的绝对值。 Asc(String) 取得字符串表达式的第一个字符ASCII 码。 Atn(number) 取得一个角度的反正切值。 CallByName (object, procname, usecalltype,[args()]) 执行一个对象的方法、设定或传回对象的属性。 CBool(expression) 转换表达式为Boolean 型态。 CByte(expression) 转换表达式为Byte 型态。 CChar(expression) 转换表达式为字符型态。 CDate(expression) 转换表达式为Date 型态。 CDbl(expression) 转换表达式为Double 型态。 CDec(expression) 转换表达式为Decimal 型态。 CInt(expression) 转换表达式为Integer 型态。 CLng(expression) 转换表达式为Long 型态
|
|
ASP.NET 页面对象模型
|
作者: Dino 加入时间: 2004-08-07 文档类型: 来自: 浏览统计: total: 20 year: 20 quarter: 20 month: 20 week: 9 today: 4
摘要:了解为 ASP.NET Web 页面建立的事件模型,以及 Web 页面转变为 HTML 过程中的各个阶段。ASP.NET HTTP 运行时负责管理对象管道,这些对象首先将请求的 URL 转换成 Page 类的具体实例,然后再将这些实例转换成纯 HTML 文本。本文将探讨那些作为页面生命周期标志的事件,以及控件和页面编写者如何干预并改变标准行为。(本文包含一些指向英文站点的链接。)
目录
简介 真正的 Page 类 页面的生命周期 执行的各个阶段 小结
简介
对由 Microsoft® Internet 信息服务 (IIS) 处理的 Microsoft® ASP.NET 页面的每个请求都会被移交到 ASP.NET HTTP 管道。HTTP 管道由一系列托管对象组成,这些托管对象按顺序处理请求,并将 URL 转换为纯 HTML 文本。HTTP 管道的入口是 HttpRuntime 类。ASP.NET 结构为辅助进程中的每个 AppDomain 创建一个此类的实例。(请注意,辅助进程为每个当前正在运行的 ASP.NET 应用程序维护一个特定的 AppDomain。)
HttpRuntime 类从内部池中获取 HttpApplication 对象,并安排此对象来处理请求。HTTP 应用程序管理器完成的主要任务就是找到将真正处理请求的类。当请求 .aspx 资源时,处理程序就是页面处理程序,即从 Page 继承的类的实例。资源类型和处理程序类型之间的关联关系存储在应用程序的配置文件中。更确切地说,默认的映射集是在 machine.config 文件的 <httpHandlers> 部分定义的。但是,应用程序可以在本地的 web.config 文件中自定义自己的 HTTP 处理程序列表。以下这一行代码就是用来为 .aspx 资源定义 HTTP 处理程序的。<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
扩展名可以与处理程序类相关联,并且更多是与处理程序工厂类相关联。在所有情况下,负责处理请求的 HttpApplication 对象都会获得一个实现 IHttpHandler 接口的对象。如果根据 HTTP 处理程序来解析关联的资源/类,则返回的类将直接实现接口。如果资源被绑定到处理程序工厂,则还需要额外的步骤。处理程序工厂类实现 IHttpHandlerFactory 接口,此接口的 GetHandler 方法将返回一个基于 IHttpHandler 的对象。
HTTP 运行时是如何结束这个循环并处理页面请求的?ProcessRequest 方法在 IHttpHandler 接口中非常重要。通过对代表被请求页面的对象调用此方法,ASP.NET 结构会启动将生成浏览器输出的进程。
真正的 Page 类
特定页面的 HTTP 处理程序类型取决于 URL。首次调用 URL 时,将构建一个新的类,这个类被动态编译为一个程序集。检查 .aspx 资源的分析进程的结果是类的源代码。该类被定义为命名空间 ASP 的组成部分,并且被赋予了一个模拟原始 URL 的名称。例如,如果 URL 的终点是 page.aspx,则类的名称就是 ASP.Page_aspx。不过,类的名称可以通过编程方式来控制,方法是在 @Page 指令中设置 ClassName 属性。
HTTP 处理程序的基类是 Page。这个类定义了由所有页面处理程序共享的方法和属性的最小集合。Page 类实现 IHttpHandler 接口。
在很多情况下,实际处理程序的基类并不是 Page,而是其他的类。例如,如果使用了代码分离,就会出现这种情况。代码分离是一项开发技术,它可以将页面所需的代码隔离到单独的 C# 和 Microsoft Visual Basic® .NET 类中。页面的代码是一组事件处理程序和辅助方法,这些处理程序和方法真正决定了页面的行为。可以使用 <script runat=server> 标记对此代码进行内联定义,或者将其放置在外部类(代码分离类)中。代码分离类是从 Page 继承并使用额外的方法的类,被指定用作 HTTP 处理程序的基类。
还有一种情况,HTTP 处理程序也不是基于 Page 的,即在应用程序配置文件的 <pages> 部分中,包含了 PageBaseType 属性的重新定义。<pages PageBaseType="Classes.MyPage, mypage" />
PageBaseType 属性指明包含页面处理程序的基类的类型和程序集。从 Page 导出的这个类可以自动赋予处理程序扩展的自定义方法和属性集。
页面的生命周期
完全识别 HTTP 页面处理程序类后,ASP.NET 运行时将调用处理程序的 ProcessRequest 方法来处理请求。通常情况下,无需更改此方法的实现,因为它是由 Page 类提供的。
此实现将从调用为页面构建控件树的 FrameworkInitialize 方法开始。FrameworkInitialize 方法是 TemplateControl 类(Page 本身从此类导出)的一个受保护的虚拟成员。所有为 .aspx 资源动态生成的处理程序都将覆盖 FrameworkInitialize。在此方法中,构建了页面的整个控件树。
接下来,ProcessRequest 使页面经历了各个阶段:初始化、加载视图状态信息和回发数据、加载页面的用户代码以及执行回发服务器端事件。之后,页面进入显示模式:收集更新的视图状态,生成 HTML 代码并随后将代码发送到输出控制台。最后,卸载页面,并认为请求处理完毕。
在各个阶段中,页面会触发少数几个事件,这些事件可以由 Web 控件和用户定义的代码截取并进行处理。其中的一些事件是嵌入式控件专用的,因此无法在 .aspx 代码级进行处理。
要处理特定事件的页面应该明确注册一个适合的处理程序。不过,为了向后兼容早期的 Visual Basic 编程风格,ASP.NET 也支持隐式事件挂钩的形式。默认情况下,页面会尝试将特定的方法名称与事件相匹配,如果实现匹配,则认为此方法就是匹配事件的处理程序。ASP.NET 提供了六种方法名称的特定识别,它们是 Page_Init、Page_Load、Page_DataBind、Page_PreRender 和 Page_Unload。这些方法被认为是由 Page 类提供的相应事件的处理程序。HTTP 运行时会自动将这些方法绑定到页面事件,这样,开发人员就不必再编写所需的粘接代码了。例如,如果命名为 Page_Load 的方法绑定到页面的 Load 事件,则可省去以下代码。this.Load += new EventHandler(this.Page_Load);
对特定名称的自动识别是由 @Page 指令的 AutoEventWireup 属性控制的。如果该属性设置为 false,则要处理事件的所有应用程序都需要明确连接到页面事件。不使用自动绑定事件的页面性能会稍好一些,因为不需要额外匹配名称与事件。请注意,所有 Microsoft Visual Studio® .NET 项目都是在禁用 AutoEventWireup 属性的情况下创建的。但是,该属性的默认设置是 true,即 Page_Load 等方法会被识别,并被绑定到相关联的事件。
下表中按顺序列出了页面的执行包括的几个阶段,执行的标志是一些应用程序级的事件和/或受保护并可覆盖的方法。
表 1:ASP.NET 页面生命中的关键事件
阶段
页面事件
可覆盖的方法
页面初始化
Init
加载视图状态
LoadViewState
处理回发数据
任意实现 IPostBackDataHandler 接口的控件中的 LoadPostData 方法
加载页面
Load
回发更改通知
任意实现 IPostBackDataHandler 接口的控件中的 RaisePostDataChangedEvent 方法
处理回发事件
由控件定义的任意回发事件
任意实现 IPostBackDataHandler 接口的控件中的 RaisePostBackEvent 方法
页面显示前阶段
PreRender
保存视图状态
SaveViewState
显示页面
Render
卸载页面
Unload
以上所列的阶段中有些在页面级是不可见的,并且仅对服务器控件的编写者和要创建从 Page 导出的类的开发人员有意义。Init、Load、PreRender、Unload,再加上由嵌入式控件定义的所有回发事件,就构成了向外发送页面的各个阶段标记。
执行的各个阶段
页面生命周期中的第一个阶段是初始化。这个阶段的标志是 Init 事件。在成功创建页面的控件树后,将对应用程序触发此事件。换句话说,当 Init 事件发生时,.aspx 源文件中静态声明的所有控件都已实例化并采用各自的默认值。控件可以截取 Init 事件以初始化在传入的 Web 请求的生命周期内所需的所有设置。例如,这时控件可以加载外部模板文件或设置事件的处理程序。请注意,这时视图状态信息尚不可用。
初始化之后,页面框架将加载页面的视图状态。视图状态是名称/值对的集合,在此集合中,控件和页面本身存储了对所有 Web 请求都必须始终有效的全部信息。视图状态代表了页面的调用上下文。通常,它包含上次在服务器上处理页面时控件的状态。首次在会话中请求页面时,视图状态为空。默认情况下,视图状态存储在静默添加到页面的隐藏字段中,该字段的名称是 __VIEWSTATE。通过覆盖 LoadViewState 方法(Control 类的受保护、可覆盖方法),组件开发人员可以控制视图状态的存储方式以及视图状态的内容映射到内部状态的方式。
有些方法(如 LoadPageStateFromPersistenceMedium 以及其对应的 SavePageStateToPersistenceMedium),可以用来将视图状态加载并保存到其他存储介质(例如会话、数据库或服务器端文件)中。与 LoadViewState 不同,上述方法只能在从 Page 导出的类中使用。
存储视图状态之后,页面树中控件的状态与页面最后一次显示在浏览器中的状态相同。下一步是更新它们的状态以加入客户端的更改。处理回发数据阶段使控件有机会更新其状态,从而准确反映客户端相应的 HTML 元素的状态。例如,服务器的 TextBox 控件对应的 HTML 元素是 <input type=text>。在回发数据阶段,TextBox 控件将检索 <input> 标记的当前值,并使用该值来刷新自己内部的状态。每个控件都要从回发的数据中提取值并更新自己的部分属性。TextBox 控件将更新它的 Text 属性,而 CheckBox 控件将刷新它的 Checked 属性。服务器控件和 HTML 元素的对应关系可以通过二者的 ID 找到。
在处理回发数据阶段的最后,页面中的所有控件的状态都将使用客户端输入的更改来更新前一状态。这时,将对页面触发 Load 事件。
页面中可能会有一些控件,当其某个敏感属性在两个不同的请求中被修改时,需要完成特定的任务。例如,如果 TextBox 控件的文本在客户端被修改,则此控件将触发 TextChanged 事件。每个控件在其一个或多个属性被修改为客户端输入的值时都可以决定触发相应的事件。对于这些更改对其非常关键的控件,控件实现 IPostBackDataHandler 接口,此接口的 LoadPostData 方法是在 Load 事件后立即调用的。通过对 LoadPostData 方法进行编码,控件将验证自上次请求后是否发生了关键更改,并触发自己的更改事件。
页面生命周期中的关键事件是被调用以执行服务器端代码的事件,此代码与客户端触发的事件相关联。当用户单击按钮时,将回发页面。回发值的集合中包括启动整个操作的按钮的 ID。如果控件实现 IPostBackEventHandler 接口(如按钮和链接按钮),页面框架将调用 RaisePostBackEvent 方法。此方法的行为取决于控件的类型。就按钮和链接按钮而言,此方法将查找 Click 事件处理程序并运行相关的委托。
处理完回发事件之后,页面就可以显示了。这个阶段的标志是 PreRender 事件。控件可以利用这段时间来执行那些需要在保存视图状态和显示输出的前一刻执行的更新操作。下一个状态是 SaveViewState,在此状态中,所有控件和页面本身都将更新自己 ViewState 集合的内容。然后,将得到序列化、散列、Base64 编码的视图状态,而且此视图状态与隐藏字段 __VIEWSTATE 相关联。
通过覆盖 Render 方法可以改变各个控件的显示机制。此方法接受 HTML 书写器对象,并使用此对象来积累所有要为控件生成的 HTML 文本。Page 类的 Render 方法的默认实现包括对所有成员控件的递归调用。对于每个控件,页面都将调用 Render 方法,并缓存 HTML 输出。
页面生命中的最后一个标志是 Unload 事件,在页面对象消除之前发生。在此事件中,您应该释放所有可能占用的关键资源(例如文件、图形对象、数据库连接等)。
在此事件之后,也就是最后,浏览器接收 HTTP 响应数据包并显示页面。
小结
ASP.NET 页面对象模型因其事件机制而显得格外新颖独特。Web 页面由控件组成,这些控件既可以产生丰富的基于 HTML 的用户界面,又可以通过事件与用户交互。以前,在 Web 应用程序的上下文中设置事件模型是件有挑战性的工作。可我们惊奇的看到,客户端生成的事件可以由服务器端的代码来解决,而且只进行一些相应的修改后,此过程仍可以输出相同的 HTML 页面。
掌握这个模型对于了解页面生命周期的各个阶段,以及页面对象如何被 HTTP 运行时实例化并使用是非常重要的。
关于作者
Dino Esposito 是一位来自意大利罗马的培训教师和顾问。作为 Wintellect 团队的成员,Dino 专门研究 ASP.NET 和 ADO.NET,主要在欧洲和美国从事教学和咨询工作。此外,Dino 还负责管理 Wintellect 的 ADO.NET 课件,并为 MSDN 期刊的“Cutting Edge”专栏撰写文章。要与他联系,请向 dinoe@wintellect.com 发送电子邮件。 |
|
ASP.NET 中如何防范SQL注入式攻击
|
一、什么是SQL注入式攻击? 所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。常见的SQL注入式攻击过程类如: ⑴ 某个ASP.NET Web应用有一个登录页面,这个登录页面控制着用户是否有权访问应用,它要求用户输入一个名称和密码。 ⑵ 登录页面中输入的内容将直接用来构造动态的SQL命令,或者直接用作存储过程的参数。下面是ASP.NET应用构造查询的一个例子: System.Text.StringBuilder query = new System.Text.StringBuilder("SELECT * from Users WHERE login = '")。Append(txtLogin.Text)。Append("' AND password='")。Append(txtPassword.Text)。Append("'"); ⑶ 攻击者在用户名字和密码输入框中输入"'或'1'='1"之类的内容。 ⑷ 用户输入的内容提交给服务器之后,服务器运行上面的ASP.NET代码构造出查询用户的SQL命令,但由于攻击者输入的内容非常特殊,所以最后得到的SQL命令变成:SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'. ⑸ 服务器执行查询或存储过程,将用户输入的身份信息和服务器中保存的身份信息进行对比。 ⑹ 由于SQL命令实际上已被注入式攻击修改,已经不能真正验证用户身份,所以系统会错误地授权给攻击者。 如果攻击者知道应用会将表单中输入的内容直接用于验证身份的查询,他就会尝试输入某些特殊的SQL字符串篡改查询改变其原来的功能,欺骗系统授予访问权限。 系统环境不同,攻击者可能造成的损害也不同,这主要由应用访问数据库的安全权限决定。如果用户的帐户具有管理员或其他比较高级的权限,攻击者就可能对数据库的表执行各种他想要做的操作,包括添加、删除或更新数据,甚至可能直接删除表。 二、如何防范? 好在要防止ASP.NET应用被SQL注入式攻击闯入并不是一件特别困难的事情,只要在利用表单输入的内容构造SQL命令之前,把所有输入内容过滤一番就可以了。过滤输入内容可以按多种方式进行。 ⑴ 对于动态构造SQL查询的场合,可以使用下面的技术: 第一:替换单引号,即把所有单独出现的单引号改成两个单引号,防止攻击者修改SQL命令的含义。再来看前面的例子,“SELECT * from Users WHERE login = ''' or ''1''=''1' AND password = ''' or ''1''=''1'”显然会得到与“SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'”不同的结果。 第二:删除用户输入内容中的所有连字符,防止攻击者构造出类如“SELECT * from Users WHERE login = 'mas' —— AND password =''”之类的查询,因为这类查询的后半部分已经被注释掉,不再有效,攻击者只要知道一个合法的用户登录名称,根本不需要知道用户的密码就可以顺利获得访问权限。 第三:对于用来执行查询的数据库帐户,限制其权限。用不同的用户帐户执行查询、插入、更新、删除操作。由于隔离了不同帐户可执行的操作,因而也就防止了原本用于执行SELECT命令的地方却被用于执行INSERT、UPDATE或DELETE命令。 ⑵ 用存储过程来执行所有的查询。SQL参数的传递方式将防止攻击者利用单引号和连字符实施攻击。此外,它还使得数据库权限可以限制到只允许特定的存储过程执行,所有的用户输入必须遵从被调用的存储过程的安全上下文,这样就很难再发生注入式攻击了。 ⑶ 限制表单或查询字符串输入的长度。如果用户的登录名字最多只有10个字符,那么不要认可表单中输入的10个以上的字符,这将大大增加攻击者在SQL命令中插入有害代码的难度。 ⑷ 检查用户输入的合法性,确信输入的内容只包含合法的数据。数据检查应当在客户端和服务器端都执行——之所以要执行服务器端验证,是为了弥补客户端验证机制脆弱的安全性。 在客户端,攻击者完全有可能获得网页的源代码,修改验证合法性的脚本(或者直接删除脚本),然后将非法内容通过修改后的表单提交给服务器。因此,要保证验证操作确实已经执行,唯一的办法就是在服务器端也执行验证。你可以使用许多内建的验证对象,例如RegularExpressionValidator,它们能够自动生成验证用的客户端脚本,当然你也可以插入服务器端的方法调用。如果找不到现成的验证对象,你可以通过CustomValidator自己创建一个。 ⑸ 将用户登录名称、密码等数据加密保存。加密用户输入的数据,然后再将它与数据库中保存的数据比较,这相当于对用户输入的数据进行了“消毒”处理,用户输入的数据不再对数据库有任何特殊的意义,从而也就防止了攻击者注入SQL命令。System.Web.Security.FormsAuthentication类有一个HashPasswordForStoringInConfigFile,非常适合于对输入数据进行消毒处理。 ⑹ 检查提取数据的查询所返回的记录数量。如果程序只要求返回一个记录,但实际返回的记录却超过一行,那就当作出错处理。 |
|
Asp.net动态生成html页面
|
作者: love610 加入时间: 2004-09-21 文档类型: 来自: 浏览统计: total: 31 year: 31 quarter: 31 month: 31 week: 15 today: 2
最近研究一个新闻系统,找到了关于asp.net生成HTML的资料
思路
1. 利用如Dw-Mx这样的工具生成html格式的模板,在需要添加格式的地方加入特殊标记(如$htmlformat$),动态生成文件时利用代码读取此模板,然后获得前台输入的内容,添加到此模板的标记位置中,生成新文件名后写入磁盘,写入后再向数据库中写入相关数据。
2. 使用后台代码硬编码Html文件,可以使用HtmlTextWriter类来写html文件。
优点
1. 可以建立非常复杂的页面,利用包含js文件的方法,在js文件内加入document.write()方法可以在所有页面内加入如页面头,广告等内容。
2. 静态html文件利用MS Windows2000的Index Server可以建立全文搜索引擎,利用asp.net可以以DataTable的方式得到搜索结果。而Win2000的Index服务无法查找xml文件的内容。如果包括了数据库搜索与Index索引双重查找,那么此搜索功能将非常强大。
3. 节省服务器的负荷,请求一个静态的html文件比一个aspx文件服务器资源节省许多。
缺点
思路二: 如果用硬编码的方式,工作量非常大,需要非常多的html代码。调试困难。而且使用硬编码生成的html样式无法修改,如果网站更换样式,那么必须得重新编码,给后期带来巨大的工作量。
因此这里采用的是第一种思路
示列代码
1.定义(template.htm)html模板页面
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body >
<table $htmlformat[0] height="100%" border="0" width="100%" cellpadding="10" cellspacing="0" bgcolor="#eeeeee" style="border:1px solid #000000">
<tr>
<td width="100%" valign="middle" align="left">
<span style="color: $htmlformat[1];font-size: $htmlformat[2]">$htmlformat[3]</span>
</td>
</tr>
</table>
</body>
</html>
2.asp.net代码:
//---------------------读html模板页面到stringbuilder对象里----
string[] format=new string[4];//定义和htmlyem标记数目一致的数组
StringBuilder htmltext=new StringBuilder();
try
{
using (StreamReader sr = new StreamReader("存放模板页面的路径和页面名"))
{
String line;
while ((line = sr.ReadLine()) != null)
{
htmltext.Append(line);
}
sr.Close();
}
}
catch
{
Response.Write("<Script>alert('读取文件错误')</Script>");
}
//---------------------给标记数组赋值------------
format[0]="background=\"bg.jpg\"";//背景图片
format[1]= "#990099";//字体颜色
format[2]="150px";//字体大小
format[3]= "<marquee>生成的模板html页面</marquee>";//文字说明
//----------替换htm里的标记为你想加的内容
for(int i=0;i<4;i++)
{
htmltext.Replace("$htmlformat["+i+"]",format[i]);
}
//----------生成htm文件------------------――
try
{
using(StreamWriter sw=new StreamWriter("存放路径和页面名",false,System.Text.Encoding.GetEncoding("GB2312")))
{
sw.WriteLine(htmltext);
sw.Flush();
sw.Close();
}
}
catch
{
Response.Write ("The file could not be wirte:");
}
小结
用此方法可以方便的生成html文件。程序使用了是循环替换,因此对需替换大量元素的模板速度非常快。 |
|
在ASP.NET中创建安全的web站点
|
以前用ASP,PHP,JSP编写网站代码的时候,站点安全性总是一件头疼的事情,虽然我们编写了用户登录,注册,验证页面,但是效果总是不理想。有时候我们不得不用大量的session变量来存放相关信息,处处设防。而在.NET环境下,这个问题处理起来就非常容易了。关键是要充分理解web.config文件。首先,介绍一下web.config文件。 <?xml version="1.0" encoding="utf-8" ?> <configuration>
<system.web>
<!-- 动态调试编译 设置 compilation debug="true" 以将调试符号(.pdb 信息) 插入到编译页中。因为这将创建执行起来 较慢的大文件,所以应该只在调试时将该值设置为 true,而所有其他时候都设置为 false。有关更多信息,请参考有关 调试 ASP.NET 文件的文档。 --> <compilation defaultLanguage="vb" debug="true" />
<!-- 自定义错误信息 设置 customErrors mode="On" 或 "RemoteOnly" 以启用自定义错误信息,或设置为 "Off" 以禁用自定义错误信息。 为每个要处理的错误添加 <error> 标记。 --> <customErrors mode="RemoteOnly" />
<!-- 身份验证 此节设置应用程序的身份验证策略。可能的模式是 “Windows”、 “Forms”、“Passport”和 “None” --> <authentication mode="Windows" />
<!-- 授权 此节设置应用程序的授权策略。可以允许或拒绝用户或角色访问 应用程序资源。通配符:"*" 表示任何人,"?" 表示匿名 (未授权的)用户。 --> <authorization> <allow users="*" /> <!-- 允许所有用户 -->
<!-- <allow users="[逗号分隔的用户列表]" roles="[逗号分隔的角色列表]"/> <deny users="[逗号分隔的用户列表]" roles="[逗号分隔的角色列表]"/> --> </authorization>
<!-- 应用程序级别跟踪记录 应用程序级别跟踪在应用程序内为每一页启用跟踪日志输出。 设置 trace enabled="true" 以启用应用程序跟踪记录。如果 pageOutput="true",则 跟踪信息将显示在每一页的底部。否则,可以通过从 Web 应用程序 根浏览 "trace.axd" 页来查看 应用程序跟踪日志。 --> <trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
<!-- 会话状态设置 默认情况下,ASP.NET 使用 cookie 标识哪些请求属于特定的会话。 如果 cookie 不可用,则可以通过将会话标识符添加到 URL 来跟踪会话。 若要禁用 cookie,请设置 sessionState cookieless="true"。 --> <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;user id=sa;password=" cookieless="false" timeout="20" />
<!-- 全球化 此节设置应用程序的全球化设置。 --> <globalization requestEncoding="utf-8" responseEncoding="utf-8" />
</system.web>
</configuration>
好了,相信看过上面的介绍以后,对web.config文件一定非常了解了吧。下面我们就切入主题。为了防止用户没有经过验证就访问站点,我们的处理方法是当用户没有通过验证的时候点击任何页面将会直接跳到Login.aspx页面,具体代码如下:
<authentication mode="Forms"> <forms name="yourAuthCookie" loginUrl="login.aspx" protection="All" path="/" /> </authentication> <authorization> <deny users="?" /> </authorization> 但是这样会产生一个问题,那就是如果我的站点有一些信息是可以让任意用户随意访问的,比如站点简介,使用说明等。如果按照上面的处理方法岂不让用户觉得很麻烦,呵呵,不急,在ASP.NET中自然有相应的解决办法。下面的代码可以实现匿名用户访问Test.aspx页面:
<location path="test.aspx"> <system.web> <authorization> <allow users="?" /> </authorization> </system.web> </location>
解决了上面两个问题,相信大家心里一定有底了吧。下面就开始实现login.aspx页面。利用C#和SQL Server2000,创建一个webform页面,加入相应的控件。具体代码如下: 代码运行框: <%@ Page language="c#" Codebehind="login.aspx.cs"
AutoEventWireup="false" Inherits="secure.login" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>Secure Site</title>
<meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="login" method="post" runat="server">
<table cellSpacing="0" cellPadding="0" border="0">
<tr>
<td vAlign="top" align="left">
<asp:label id="Message" Runat="server" ForeColor="#ff0000">
</asp:label>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<b>E-mail:</b>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<asp:textbox id="username" Runat="server" Width="120">
</asp:textbox>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<b>Password:</b>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<asp:textbox id="password" Runat="server"
Width="120" TextMode="Password">
</asp:textbox>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<asp:checkbox id="saveLogin" Runat="server"
Text="<b>Save my login</b>">
</asp:checkbox>
</td>
</tr>
<tr>
<td vAlign="top" align="right">
<asp:imagebutton id="btnLogin" Runat="server"
ImageUrl="/images/w2k/login/btnLogin.gif">
</asp:imagebutton>
</td>
</tr>
</table>
</form>
</body>
</HTML>
[Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行]
界面做好之后,就开始编写提交按钮事件,首先需要注册该事件,代码如下: private void InitializeComponent() { this.btnLogin.Click += new System.Web.UI.ImageClickEventHandler(this.btnLogin_Click); . . . } 事件注册好之后,自然就是编写事件处理函数了:
private void btnLogin_Click(object sender, System.Web.UI.ImageClickEventArgs e) { CCommonDB sql = new CCommonDB(); string redirect = "";
if((redirect = sql.AuthenticateUser(this.Session, this.Response, username.Text, password.Text, saveLogin.Checked)) != string.Empty) { // Redirect the user Response.Redirect(redirect); } else { Message.Text = "Login Failed!"; } } 读者看完上面的代码之后一定想问CCommonDB是哪里来的东东,这是我编写的一个类,用来处理用户登录信息的,如果成功则把相关信息写入session、Cookie和SQL数据库,同时跳到default.aspx页面。具体如下:
CCommonDB.cs
namespace secure.Components
{
public class CCommonDB : CSql
{
public CCommonDB() : base() { }
public string AuthenticateUser(
System.Web.SessionState.HttpSessionState objSession, // Session Variable
System.Web.HttpResponse objResponse, // Response Variable
string email, // Login
string password, // Password
bool bPersist // Persist login
)
{
int nLoginID = 0;
int nLoginType = 0;
// Log the user in
Login(email, password, ref nLoginID, ref nLoginType);
if(nLoginID != 0) // Success
{
// Log the user in
System.Web.Security.FormsAuthentication.SetAuthCookie(nLoginID.ToString(), bPersist);
// Set the session varaibles
objSession["loginID"] = nLoginID.ToString();
objSession["loginType"] = nLoginType.ToString();
// Set cookie information incase they made it persistant
System.Web.HttpCookie wrapperCookie = new System.Web.HttpCookie("wrapper");
wrapperCookie.Value = objSession["wrapper"].ToString();
wrapperCookie.Expires = DateTime.Now.AddDays(30);
System.Web.HttpCookie lgnTypeCookie = new System.Web.HttpCookie("loginType");
lgnTypeCookie.Value = objSession["loginType"].ToString();
lgnTypeCookie.Expires = DateTime.Now.AddDays(30);
// Add the cookie to the response
objResponse.Cookies.Add(wrapperCookie);
objResponse.Cookies.Add(lgnTypeCookie);
return "/candidate/default.aspx";
}
case 1: // Admin Login
{
return "/admin/default.aspx";
}
case 2: // Reporting Login
{
return "/reports/default.aspx";
}
default:
{
return string.Empty;
}
}
}
else
{
return string.Empty;
}
}
/// <summary>
/// Verifies the login and password that were given
/// </summary>
/// <param name="email">the login</param>
/// <param name="password">the password</param>
/// <param name="nLoginID">returns the login id</param>
/// <param name="nLoginType">returns the login type</param>
public void Login(string email, string password, ref int nLoginID, ref int nLoginType)
{
ResetSql();
DataSet ds = new DataSet();
// Set our parameters
SqlParameter paramLogin = new SqlParameter("@username", SqlDbType.VarChar, 100);
paramLogin.Value = email;
SqlParameter paramPassword = new SqlParameter("@password", SqlDbType.VarChar, 20);
paramPassword.Value = password;
Command.CommandType = CommandType.StoredProcedure;
Command.CommandText = "glbl_Login";
Command.Parameters.Add(paramLogin);
Command.Parameters.Add(paramPassword);
Adapter.TableMappings.Add("Table", "Login");
Adapter.SelectCommand = Command;
Adapter.Fill(ds);
if(ds.Tables.Count != 0)
{
DataRow row = ds.Tables[0].Rows[0];
// Get the login id and the login type
nLoginID = Convert.ToInt32(row["Login_ID"].ToString());
nLoginType = Convert.ToInt32(row["Login_Type"].ToString());
}
else
{
nLoginID = 0;
nLoginType = 0;
}
}
}
abstract public class CSql
{
private SqlConnection sqlConnection; // Connection string
private SqlCommand sqlCommand; // Command
private SqlDataAdapter sqlDataAdapter; // Data Adapter
private DataSet sqlDataSet; // Data Set
public CSql()
{
sqlConnection = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);
sqlCommand = new SqlCommand();
sqlDataAdapter = new SqlDataAdapter();
sqlDataSet = new DataSet();
sqlCommand.Connection = sqlConnection;
}
/// <summary>
/// Access to our sql command
/// </summary>
protected SqlCommand Command
{
get { return sqlCommand; }
}
/// <summary>
/// Access to our data adapter
/// </summary>
protected SqlDataAdapter Adapter
{
get { return sqlDataAdapter; }
}
/// <summary>
/// Makes sure that everything is clear and ready for a new query
/// </summary>
protected void ResetSql()
{
if(sqlCommand != null)
{
sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
}
if(sqlDataAdapter != null)
sqlDataAdapter = new SqlDataAdapter();
if(sqlDataSet != null)
sqlDataSet = new DataSet();
}
/// <summary>
/// Runs our command and returns the dataset
/// </summary>
/// <returns>the data set</returns>
protected DataSet RunQuery()
{
sqlDataAdapter.SelectCommand = Command;
sqlConnection.Open();
sqlConnection.Close();
sqlDataAdapter.Fill(sqlDataSet);
return sqlDataSet;
}
}
}
|
|
从零开始学ASP.NET(基础篇)
|
作者: 蓝鲸 加入时间: 2004-11-01 文档类型: 来自: 5D多媒体 浏览统计: total: 59 year: 59 quarter: 59 month: 59 week: 21 today: 2
前言
来这儿学习ASP或ASPNET的朋友越来越多了,并且初学的要占了很多,或许是6x%,或许是7x%。当斑竹的主倒楣,本来一个人学得很轻松的,想写就写一点,没事了来凑凑热闹。可现在,发觉一些朋友学ASPNET的路还没找熟,包括自己。 学ASPNET与ASP有区别,这种区别不是语言上的,而是思路上的区别。ASP是纯面向过程的,而ASPNET是完全面向对向的。这种区别使我们在编程的结构设计上要与ASP有很大的不同。 废话少说了,现在我也和各位一起从零开始。我用C#,其实用VB.NET的朋友也应该可以看懂,我会在不同之处说明一些区别的。
第一天
学习目的:
掌握最基本的Label、TextBox、Button控件用法
掌握用StringBuider类连接字符串
理解服务器的环境变量
StringBuilder类: 命名空间是:System.Text。
StringBuilder类是个高效的类,StringBuilder.Append连接字符串的方法是非常快的。用于连接大量的字符串,其速度的优越性就会体现出来。
先举几个例子: 在cs或vb文件的头部加上 [C#]using System.Text; [VB]Imports System.Text
[C#]StringBuilder sbFirst = new StringBuilder(); sbFirst.Append(“这是第一个学ASPNET的例子</br>”); sbFirst.Append( “这个例子太简单</br>”); sbFirst.Append( “连三岁小陔都会做,我早知道了,嘿嘿。”); Response.Write(sbFirst.ToString());
[VB]Dim sbFirst As StringBuilder = New StringBuilder() sbFirst.Append(“这是第一个学ASPNET的例子</br>”) sbFirst.Append( “这个例子太简单</br>”) sbFirst.Append( “连三岁小陔都会做,我早知道了,嘿嘿。”) Response.Write(sbFirst.ToString)
下面就可以做正题了: 先建立一个C#的WEB应用程序工程,这废话我就少说了吧。 放一个Button控件:ID为btnShowVariable 放一个Label控件:ID为labServerVariable
添加Button的单击事件,如下代码 private void btnShowVariable_Click(object sender, System.EventArgs e) { labServerVariables.Text = "";
StringBuilder info = new StringBuilder();
foreach (object objVar in Request.ServerVariables) { info.Append("<span style='font-size:9pt'>"); info.Append(objVar.ToString()); info.Append(" = <font color=blue>"); info.Append(Request.ServerVariables[objVar.ToString()]); info.Append("</font></span><br>"); }
labServerVariables.Text = info.ToString(); }
这样我们就可以这样用 Response.Write(Request.ServerVariables["REMOTE_ADDR"]); // IP地址 Response.Write("<BR>"); Response.Write(Request.ServerVariables["URL"]); // 网页的URL
第二天
学习目的:
掌握文本框的用法
初次接触try…catch…语法
今天内容很轻松,用一个例子,输入年月日,判断输入是否正确
图片如下:
用个文本框,ID分别为txtYear,txtMonth,txtDate; 检验按钮的代码为: private void btnCheck_Click(object sender, System.EventArgs e) { int year, month, date;
// 先把输入的字符转成int类型,如果非数字型, // 会触发错误 try { year = Convert.ToInt32(txtYear.Text); month = Convert.ToInt32(txtMonth.Text); date = Convert.ToInt32(txtDate.Text); } catch { labCheckInfo.Text = "输入的是非数字字符。"; return; }
// 如果第一步检验合格,就把输入的数字转化为日期格式 // 如果不符合日期格式即引发错误 try { DateTime dt = new DateTime(year, month, date); } catch { labCheckInfo.Text = "输入的数字不符合日期格式"; return; }
labCheckInfo.Text = "输入正确"; }
第三天
学习目的:
掌握下拉列表框的用法,并理解AutoPostBack属性;
理解IsPoskBack及用法;
初识DataTable的增加列、行,与下拉列表框绑定的方法。
今天的内容稍多些,而且涉及一些比较常用的,如IsPostBack及DataTable的基本用法。
知识点: IsPostBack:在页面onLoad之间是false值,而当从服务器回传后,该值变为true。当页面中的Button或ImageButton等触发事件,都会把表单回传到服务器,而返回时又会引发onLoad事件。为了节省服务器资源,有些加载中需进行一次,而不需要在回传后多次发生,可以用!IsPoskBack来作为条件,那么页面第一次加载后,以后就不会发生。该属性可以帮助你提高程序的性能。 DataTable:即数据表,.Net 程序中最常用的类,特别是数据库开发中,没有该类的程序是不可想象的。
先做个小程序来练练手,很简单,就一个下拉菜单,取名dlstWeb。在属性的Itmes选项中打开以下对话框,添加各项:
图片如下:
ASPX中的代码为: <asp:DropDownList id="dlstWeb" style="Z-INDEX: 101; LEFT: 32px; POSITION: absolute; TOP: 32px" runat="server" Width="88px" AutoPostBack="True"> <asp:ListItem value="http://www.sina.com.cn">新浪 </asp:ListItem> <asp:ListItem value="http://www.sohu.com">搜狐</asp:ListItem> <asp:ListItem value="http://www.163.com">网易</asp:ListItem> </asp:DropDownList>
在下拉框的SelectedIndexChanged事件中的加入代码: private void dlstWeb_SelectedIndexChanged(object sender, System.EventArgs e) { Response.Write("<script language=javascript>window.open('" +dlstWeb.Selectedvalue + "');</script>"); }
按F5运行,可是我们发现这下拉框选择时什么事也没发生。原来原因是出在下拉框的AutoPostBack属性上,把它设为true后再试试,一切OK了。 下面我们增加些难度,下拉框中的内容很多情况下不是事先固定的,而是要动态添加。这里设计是用一数据表DataTable与之联系起来。
另建一文件,按上添加一下拉框,取名dlstWeb,先设AutoPostPack为false,否则在刚启动而面就触发SelectedIndexChanged事件,弹出窗口就乱飞了。 在onLoad事件中添加代码,注意DataTable用法及IsPoskBack DataTable属于System.Data命名空间,所以如果页面没预添加,可以自行增加这一行。
private void Page_Load(object sender, System.EventArgs e) { // 用IsPostBack判断,只在没有回传时才初始化 // 这样可以防止每次刷新或回传时,都执行一次以下代码 // 可以节省服务器的资源了。 if (!IsPostBack) { DataTable dt = new DataTable(); DataRow dr;
// 在表中增加字段 dt.Columns.Add("WebName", typeof(string)); dt.Columns.Add("WebUrl", typeof(string));
// 表中增加行 dr = dt.NewRow(); dr["WebName"] = "新浪"; dr["WebUrl"] = "http://www.sina.com.cn"; dt.Rows.Add(dr);
dr = dt.NewRow(); dr["WebName"] = "网易"; dr["WebUrl"] = "http://www.163.com"; dt.Rows.Add(dr);
dr = dt.NewRow(); dr["WebName"] = "搜狐"; dr["WebUrl"] = "http://www.sohu.com"; dt.Rows.Add(dr);
// 把表与下拉菜单绑定数据 dlstWeb.DataSource = dt; dlstWeb.DataTextField = "WebName"; dlstWeb.DatavalueField = "WebUrl"; dlstWeb.DataBind();
// 开始时就把下拉菜单的AutoPostBack设为false, // 防止一开始就乱跳出网页来 dlstWeb.AutoPostBack = true; } }
下面的事件与前面一模一样了 private void dlstWeb_SelectedIndexChanged(object sender, System.EventArgs e) { Response.Write("<script language=javascript>window.open('" +dlstWeb.Selectedvalue + "');</script>"); }
小结:今天的一些知识非常重要,为了理解,程序的难度并不高。但这是以后程序设计的基础,所以这些你一定要掌握。
注:VB.NET增加字段代码稍有不同,如下:
// 在表中增加字段 dt.Columns.Add("WebName", GetType(String)) dt.Columns.Add("WebUrl", GetType(String))
其它都差不多了。 学习目的:
学习ADO.NET用法,并如何用DataRearder读取数据
今天练习数据库的最基本用法,如何打开数据库。首先在网站设置文件web.config文件的<configuration>下方加入以下节点:
<configuration>
<appSettings> <add key="数据库1" value="ex01.mdb" /> </appSettings>
……
该节点设置了数据库的路径,这样就可以很方便的调用数据库文件了,调用方法为: Server.MapPath(ConfigurationSettings.AppSettings["数据库1"]) 这是ASP.NET程序的通用方法,以后介绍的SQL SERVER数据库也是在此设置的。 好开始做程序,首先在CS文件的头部加入: using System.Configuration; using System.Data.OleDb; using System.Text; 以下在Page的Load事件中,读取ACCESS数据库,并用表格显示出来: private void Page_Load(object sender, System.EventArgs e) { StringBuilder sbTable = new StringBuilder(); // 用于输出表格的语句
string strConnection = "Provider=Microsoft.Jet.Oledb.4.0;Data Source=" + Server.MapPath(ConfigurationSettings.AppSettings["数据库1"]);
// 连接数据库的语句 OleDbConnection conn = new OleDbConnection(strConnection); // 建立DbCommand对象 OleDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "SELECT * FROM Book";
// 打开数据库 conn.Open();
// 用DataReader读取数据 OleDbDataReader dr = cmd.ExecuteReader();
sbTable.Append("<table cellSpacing='0' cellPadding='0' border='1'><tr>"); sbTable.Append("<td>书名</td><td>作者</td><td>单价<td></tr>"); while (dr.Read()) { sbTable.Append("<tr><td>"); sbTable.Append(dr["BookTitle"].ToString()); sbTable.Append("</td><td>"); sbTable.Append(dr["Author"].ToString()); sbTable.Append("</td><td>"); sbTable.Append(dr["UnitPrice"].ToString()); sbTable.Append("</td><tr>"); } sbTable.Append("</tr></table>");
// 记住dr用毕必须关闭,否则会阻塞服务器 dr.Close();
// DbConnection是受托管的,可以不关闭 // 但为良好的编程习惯,应该关闭 conn.Close();
Response.Write(sbTable.ToString());
} 显示结果
学习目的:
掌握ADO.NET打开SQL SERVER数据库的方法。
今天做个非常普通的例子,做一个用户登录框。主要是通过这个练习认识一下SQL SERVER数据库的连接方法。和昨天的例子方法基本相同,很容易掌握的。 先建立SQL SERVER数据库,库名为AspNetABC,并建立一Member新表,建表SQL如下:
CREATE TABLE [dbo].[Member] ( [MemberID] [int] IDENTITY (1, 1) NOT NULL , [MemberName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL , [Password] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL , [Gender] [bit] NOT NULL , [Birthday] [datetime] NULL , [Email] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY]
与上一例子差不多,在web.config文件中再增加一行: <appSettings> <add key="数据库1" value="ex01.mdb" /> <add key="SqlDatabase1" value="data source=localhost;user id=sa;password=sa;initial catalog=AspNetABC;Connect Timeout=30" /> </appSettings>
在面中添加二个文本框,txtMemberName、txtPassword,并设置txtPassword的TextMode为Password。设置按钮btnLogin。btnLogin的事件代码如下:
private void btnLogin_Click(object sender, System.EventArgs e) { // 先检验输入正确性 if (txtMemberName.Text == String.Empty || txtMemberName.Text.Trim() == "") { Response.Write("<script language=javascript>alert('帐号不能为空')</script>"); return; } if (txtPassword.Text == String.Empty || txtPassword.Text.Trim() == "") { Response.Write("<script language=javascript>alert('没有输入密码')</script>"); return; }
string strConnection = ConfigurationSettings.AppSettings["SqlDatabase1"]; string sqlMember = "SELECT MemberName ,[Password] FROM Member " + " WHERE MemberName = '" + txtMemberName.Text.Trim() + "'" + " AND [Password] = '" + txtPassword.Text.Trim() + "'";
// 连接SqlServer数据库 SqlConnection conn = new SqlConnection(strConnection); // 建立SqlCommand SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = sqlMember; conn.Open(); // 建立DataReader SqlDataReader dr = cmd.ExecuteReader();
// 判断DataReader是否为空记录 if (dr.HasRows) { Response.Write("<script language=javascript>alert('" + txtMemberName.Text + "欢迎你!')</script>"); } else { Response.Write("<script language=javascript>alert('找不到该会员,或密码错误。')</script>"); }
// 千万不要忘记关闭DataReader dr.Close();
conn.Close(); }
好了,一个非常简单的登录框做好了。当然在实际程序中还应加入跳转等,这个就留给你做了。 |
|
什么是web.config
|
从文件名就可以看出是做配置用的,比如配置自定义错误页面,debug,等等 存放连接字符串是最基本的用法, 高级一点可以配置httpmodule,httphandler... 再高级一点可以写一个继承自IConfigurationSectionHandler,添加自定义的配置节... 功能是很强大的 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配置文件的语法规则 1)标识 配置内容被置于config.web文件中的标记<configuration>和</configuration>之间。 格式: <configuration> 配置内容 … </configuration>
2)配置段句柄说明 ASP.NET的配置文件架构并未指定任何文件格式或者是支持的配置属性。相反的,它提出了“配置段句柄申明”的概念来支持任意的用户定义配置段。 格式: <configsections> <add name=欲定义配置段名 type=处理的句柄函数 /> </configsections>
3)配置段 具体定义配置的内容,供应用使用。
以下例子定义了一个“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. 4ASP.NET定义的标准配置段 1)httpmodule 段: 定义了应用的http请求的处理模块以及诸如安全、日志之类的应用方式 2)httphandlers 段: 负责映射URLs到IhttpHandler类 3)sessionstat 段: 负责配置http模块的会话状态 4)globalization 段: 配置应用的公用设置 5)compilation 段: 配置ASP.NET的编译环境 6)trace 段: 配置ASP.NET的跟踪服务 7)security 段: ASP.NET的安全配置 8)iisprocessmodel 段: 在IIS上配置ASP.NET的处理模式 9)browercaps 段: 配置浏览器的兼容部件 4.2. 5一个配置读出的例子 1)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>
2)读出其内容
<!--文件名: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>
3)运行结果
4.2. 6Config.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> |
|
ADO.NET学习笔记
|
作者: firerainbow 加入时间: 2005-01-10 文档类型: 转载 来自: 浏览统计: total: 47 year: 47 quarter: 47 month: 47 week: 25 today: 4
最近几天一直在图书馆里面看《ADO.NET实用指南》,发现真是一本好书。读书自然就有心得,本人就根据书的线索,把自己的学习体会主要以代码的形式记录下来。(书上对应代码在http://www.adoguy.com/book里)
1、连接 ADO.NET最大的特色就在于支持在断开连接的情况下对数据库里的内容进行操作,这样可以大大的节约过多连接带来的消耗,前面的那一篇文章中已经给了一个具体的例子说明ADO.NET的这种特性。我们可以在从数据库里获得数据的时候打开连接,在得到数据之后就断开连接,对dataset里面的数据进行操作,然后在把dataset里的内容更新到数据库里面的时候再打开连接。对于dataReader则必须一直保持连接。 使用这种特性的时候有几点要注意一下: (1)更改连接属性的时候必须断开连接 (2)切换数据库的时候选择conn.changeDatabase(dbName),减少断开连接与新建连接往返带来的消耗 ADO.NET同时支持数据库自带连接池。在一个连接关闭之后,连接会在池中保持一段时间,然后才实际的关闭,如果在超时之前,有人请求建立相同的连接,就将打开的连接分配给请求者,这对于经常进行打开和断开的连接可以减少很多的消耗。不过在SQL SERVER 2000中采用集成安全性的连接无法入池。 连接涉及到的事件有Dispose,InfoMessage,StateChange,在MSDN可以查到,不再赘述。 模板代码: Dim conn As SqlConnection conn=New SqlConnection("……") '里面为连接字符串 conn.open() '进行相应的操作 conn.close()
2、Command对象 ADO.NET允许以三种不同的方式获取数据库里面的数据Command,DataSet,DataReader,Command是最基本的方法,通过执行SQL命令的形式获得数据。
(1)创建 可以用两种方式创建 a、创建新的Command对象 Dim cmd As New SqlCommand cmd.connection=conn cmd.CommandText="SELECT * FROM Customer" b、获得对conn中command对象的引用 Dim cmd As SqlCommand cmd=conn.createCommand(); cmd.CommandText="SELECT * FROM Customer" 推荐第二种方法
(2)执行 四种执行方式 ExecuteNonQuery() 返回受命令影响的行数 ExecuteScalar() 返回第一行第一列(使用与集函数) ExecuteReader() 返回一个DataReader对象 ExecuteXmlReader()返回一个XmlReader对象
(3)参数 主要是用在存储过程中,有复杂和精简两种形式 复杂方法: Dim param As new SqlParameter("@Return",SqlDbType.Int) param.Direction=ParameterDirection.ReturnValue cmd.Parameters.Add(param) 精简方法 cmd.Parameters.Add("@Return_value",DbType.Int32).Direction=ParameterDirection.ReturnValue 建议:如果需要处理输出值时的时候使用参数,只处理输入值的时候就不用使用参数了。
(4)事务 用SQL语句: Begin TRAN SQL操作 If @@ERROR <>0 Begin RollBack TRAN Return @@ERROR End Commit TRAN Return 0 在ADO.NET中编写事务 cmd.Transaction = conn.BeginTransaction() try { cmd.CommandText="..." cmd.ExecuteNonQuery() cmd.Transaction.commit() } catch(Exception ex) cmd.Transaction.Rollback() End try 如果希望将数据库事务处理与一些外部系统结合起来(比如在数据库更新时同时进行了WEB更新,如果WEB更新失败希望回滚事务时),选择客户端编写事务处理(用ADO.NET编写) 仅仅做数据库事务处理的话就直接在服务端写事务语句(在SQL SERVER2000 中写事务) 在事务中可以创建SavePoint来实现部分事务回滚 cmd.Transaction.save("New Customer") cmd.Transaction.Rollback("New Customer")
(5)批处理查询 如果有多条SQL语句并且可以一起执行的话,就可以进行批处理查询。在DataReader中支持批处理查询获得的数据集。 cmd.CommandText="SELECT * FROM Customer;SELECT * FROM Inovince;" Dim rdr As SqlDataReader rdr=cmd.ExecuteReader() rdr中即包含两个SQL语句执行的结果
3、DataReader对象 DataReader对象只能对查询获得的数据集进行自上而下的访问,但效率很高。如果仅仅是访问数据的话,可以使用DataReader。但DataReader要求一直连接,所以将结果的一小部分先放在内存中,读完后再从数据库中读取一部分,相当于一个缓存机制。这对于查询结果百万级的情况来说,带来的好处是显而易见的。 模板代码: Do While rdr.Read() Console.WriteLine(rdr(0)) '也可输出rdr("CustomerID") Loop 如果要进行类型限制的话可以输出(String)rdr(0)或rdr.GetString(0) 从DataReader里读出数据的时候要注意属性是否为空,如果属性可以为空,则读出数据时应进行判断 If Not rdr.IsDBNull(0) Console.writeLine(...)
用DataReader读取记录时,数据库默认上锁,可以通过更改DataReader的默认属性改变。
如果DataReader里面的数据是批处理语句执行得到的话,可以通过NextResult访问 模板代码: Do Do While rdr.Read() Console.WriteLine(rdr(0)) Loop Loop While rdr.NextResult()
处理元数据(显示每个属性的情况) Dim schema As DataTable schema=rdr.GetSchemaTable() '得到元数据表,表里的每列对应每个属性的特性集合 对于每一列属性对应的row,通过row("DataType")获得这列属性的数据类型。 |
|
一个经典的ADO.NET入门例子
|
作者: firerainbow 加入时间: 2005-01-10 文档类型: 转载 来自: 浏览统计: total: 32 year: 32 quarter: 32 month: 32 week: 12 today: 3
众所周知,ADO.NET相对于ADO的最大优势在于对于数据的更新修改可以在与数据源完全断开联系的情况下进行,然后再把数据更新情况传回到数据源。这样大大减少了连接过多对于数据库服务器资源的占用。下面是我在《ADO.NET实用指南》这本书上看到的一个例子,比较清楚的讲解了ADO.NET的使用方法。
Imports System.Data.SqlClient Imports System.Data Imports System.Data.Common
Public Class Form1 Inherits System.Windows.Forms.Form
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim conn As New SqlConnection("data source=localhost;initial catalog=StudentCourse;" & _ "User ID=;Password=;") Dim ds As New DataSet Try conn.Open() '在形成SqlDataAdapter前打开conn Dim daAuthors As New SqlDataAdapter("Select * From SC", conn) Dim bldr As New SqlCommandBuilder(daAuthors) daAuthors.Fill(ds,"SC") conn.Close() '在填充完ds后关闭连接,接着对ds进行操作
Dim tbl As New DataTable tbl = ds.Tables("SC")
Dim rowVals(3) As Object rowVals(0) = "5" rowVals(1) = "00003" rowVals(2) = "0001" rowVals(3) = 99 Dim insertedRow As DataRow insertedRow = tbl.Rows.Add(rowVals) '添加一行
tbl.Rows(0).Delete() '删除一行
tbl.Rows(1).BeginEdit() tbl.Rows(1)("score") = 89 '修改一行 tbl.Rows(1).EndEdit()
conn.Open() daAuthors.Update(ds.Tables("SC")) '须将结果传回数据源时打开连接,update conn.Close() Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub End Class |
|
Dataset初步
|
作者: 幻想曲 加入时间: 2005-01-12 文档类型: 原创 来自: 浏览统计: total: 46 year: 46 quarter: 46 month: 46 week: 13 today: 2
在一个DataSet中储存多个数据表 我们在ASP中很多人习惯于使用RecordSet对象来操作数据库,但是RecordSet有一个的缺点就是一个RecordSet只能储存一个数据表,当我们需要操作多个表时,不得不在多个RecordSet中来回操作,虽然这些在使用习惯后也没有什么,但是对一个新手来说,这也是一个很麻烦人的事情。光是那些变量名就可以搞浑你,现在好了,在ASP.Net中,只需要一个DataSet就可以完成一切。大大的方便了我们的程序。先看一段程序,再来细细讲解。
代码拷贝框 <% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<% @ Import Namespace="System.Data.ADO" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{
//联结语句
string MyConnString = "Driver={Microsoft Access Driver (*.mdb)}; DBQ=D:\test.mdb;";
string strComm1 = "select * from UserList";
string strComm2 = "select * from BookList";
//打开一个联结
ADOConnection MyConnection = new ADOConnection(MyConnString);
//打开两个DataSetCommand
ADODataSetCommand MyComm1 = new ADODataSetCommand(strComm1,MyConnection);
ADODataSetCommand MyComm2 = new ADODataSetCommand(strComm2,MyConnection);
DataSet MyDataSet = new DataSet();
//把UserList,BookList表存入DataSet
MyComm1.FillDataSet(MyDataSet,"UserList");
MyComm2.FillDataSet(MyDataSet,"BookList");
DataGrid1.DataSource = MyDataSet.Tables["UserList"].DefaultView;
DataGrid2.DataSource = MyDataSet.Tables["BookList"].DefaultView;
DataGrid1.DataBind();
DataGrid2.DataBind();
}
</script>
<html>
<head>
<title></title>
</head>
<body>
<table>
<tr>
<td>
<ASP:DataGrid id="DataGrid1" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>
</td>
<td>
<ASP:DataGrid id="DataGrid2" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>
</td>
</tr>
</table>
</body>
</html>
[Ctrl+A 全部选择 然后拷贝]
在上面的例子中,我们打开了一个名为test.mdb的Access数据库,然后把他其中的两个表"UserList"和"BookList"使用两个DataGrid控件显示出来。 我们现在来分析一下代码: string MyConnString = "Driver={Microsoft Access Driver (*.mdb)}; DBQ=D:\test.mdb;"; string strComm1 = "select * from UserList"; string strComm2 = "select * from BookList"; ADOConnection MyConnection = new ADOConnection(MyConnString); ADODataSetCommand MyComm1 = new ADODataSetCommand(strComm1,MyConnection); ADODataSetCommand MyComm2 = new ADODataSetCommand(strComm2,MyConnection); 这些都只是在作一些准备工作,打开一个联结,并且打开两个DataSetCommand取得两个表的数据。 DataSet MyDataSet = new DataSet(); 这是我们程序的关键之地,这里打开了我们要操作的DataSet对象。下面我们就需要将数据表的内容填入DataSet了。 MyComm1.FillDataSet(MyDataSet,"UserList"); MyComm2.FillDataSet(MyDataSet,"BookList"); 在一个DataSet中可以包含多种数据,这里我们是往这个名为MyDataSet的DataSet中存放了两个数据库表,其实只要愿意,我们还可以在里面插入XML数据,而且他们是不会出现冲突的。 再下面的代码,就是把MyDataSet的数据传送给DataGrid控件显示。这里就不多说了。 这里我们只是简单的说了一下DataSet能存放多个数据表的功能,大家看看好像没有什么特别的。这里看起来确实好像没有什么特别的功能,但是如果配上DataSet中的修改、添加、删除功能,我们操作数据库就变得很简单。我们可以先将数据库读入DataSet,然后在DataSet中修改数据,如果改得觉得不满意,我们还可以使用RejectChanges方法全面恢复,最后一并交给去数据库去更新。下面我们来看看如何利用DataSet和DataAdapter来操作数据库 MyConnection.Open(); //打开数据库 MyCommand.Connection = MyConnection; //设置Command MyCommand. CommandText = “select * from [admin]”; //设置Command OleDbDataAdapter MyDataAdapter = new OleDbDataAdapter(); //定义OleDbDataAdapte对象 MyDataAdapter.SelectCommand = MyCommand; //设置OleDbDataAdapte对象的SelectCommand属性 System.Data.DataSet MyDataSet = new System.Data.DataSet(); //定义DataSet MyDataAdapter.Fill(MyDataSet,"admin"); //通过OleDbDataAdapte对象的SelectCommand属性填充MyDataSet MyConnection.Close(); //关闭数据库
整个过程分以下几步: 1.建立数据库连接 2.建立OleDbDataAdapter对象! 3.实例化OleDbDataAdapter对象! 4.建立一个DataSet对象,执行SQL语句得到的表添加到其中 5.关闭数据库连接 通过上面的步骤我们就可以使用DataBind将DataSet中的数据绑定到特定的控件上了! 我们利用DataSet和DataAdapter能够更加方便的对数据库进行操作,如何通过OleDbDataAdapter来执行数据库的操作?我们只需要对DataSet中的数据进行增加、删除、修改等操作,然后在将DataSet提交给数据库即可。 //利用利用DataSet和DataAdapter操作数据库 public Boolean DoDB() { MyConnection.Open(); //打开数据库 MyCommand.Connection = MyConnection; MyCommand. CommandText = “select * from admin”; OleDbDataAdapter MyDataAdapter = new OleDbDataAdapter(); MyDataAdapter.SelectCommand = MyCommand; System.Data.DataSet MyDataSet = new System.Data.DataSet(); MyDataAdapter.Fill(MyDataSet,"admin"); //通过OleDbDataAdapte对象的SelectCommand属性填充MyDataSet
OleDbCommandBuilder MyCommandBuild = new OleDbCommandBuilder(MyDataAdapter);//关联DataSet和数据库的操作的,必不可少 foreach(DataRow dr in MyDataSet.Tables["Admin"].Rows) { if(dr["Admin_Code"].ToString().Trim().Equals("a")) { dr.Delete(); //删除DataSet 中的行 } } MyDataSet.Tables["Admin"].Rows[0][0] = "ss";//更新DataSet中第一行第一列的值 string [] dd = new String[3]{"a","b","v"}; MyDataSet.Tables["Admin"].Rows.Add(dd);//增加一行 MyDataAdapter.Update(MyDataSet,"Admin");//将DataSet中”Admin”表中的数据提交给数据库,完成数据库的更新 MyConnection.Close();//关闭数据库 }
这个程序同Command的delete、insert、update例程是执行同样的功能的,我这里改成了用MyDataAdapter来达到同样的效果!
要通过MyDataAdapter执行对数据库的操作,要有下面的几步:
1. 建立数据库连接MyConnection 2. 实例化OleDbDataAdapter对象! 3. 建立一个DataSet对象,并把执行select语句得到的记录添加到其中 4. 建立OleDbCommandBuilder对象! 并让它与我们前面的OleDbDataAdapter对象关联!语句如下:OleDbCommandBuilder MyCommandBuild = new OleDbCommandBuilder(MyDataAdapter); 5. 对DataSet中包含表的特定记录进行增加、删除、修改
6. 执行OleDbDataAdapter对象的Update命令更新数据库,语句如下: MyDataAdapter.Update(ds,"notes"); 7. 关闭数据库连接
总结: DataSet是ADO.NET中非常重要的内容,也是ADO.NET和ADO的区别的一个重要表现,特别适合成批的数据操作,也是数据棒定的重要来源。OleDbDataAdapter是DataSet和数据源之间建立联系的一个桥梁,要熟练的使用DataSet我们需要熟练的掌握OleDbDataAdapter。 |
|
如何删除表中的重复记录?
|
作者: NinGoo 加入时间: 2005-01-12 文档类型: 转载 来自: 浏览统计: total: 62 year: 62 quarter: 62 month: 62 week: 24 today: 4
--测试数据 /*----------------------------- select * from tt -----------------------------*/ id pid ----------- ----------- 1 1 1 1 2 2 3 3 3 3 3 3
(所影响的行数为 6 行)
首先,如何查询table中有重复记录 select *,count(1) as rownum from tt group by id, pid having count(1) > 1 id pid rownum ----------- ----------- ----------- 1 1 2 3 3 3
(所影响的行数为 2 行)
方法一:使用distinct和临时表 if object_id('tempdb..#tmp') is not null drop table #tmp select distinct * into #tmp from tt truncate table tt insert into tt select * from #tmp
方法二:添加标识列 alter table tt add NewID int identity(1,1) go delete from tt where exists(select 1 from tt a where a.newid>tt.newid and tt.id=a.id and tt.pid=a.pid) go alter table tt drop column NewID go
--测试结果 /*----------------------------- select * from tt -----------------------------*/ id pid ----------- ----------- 1 1 2 2 3 3 |
|
|