| 长春 的个人资料长春的共享空间照片日志列表 | 帮助 |
|
|
3月15日 《Effective C# 精髓》摘选昨天买了一本《Effective C#》,看了几个Item,虽然没有当初读《Effective C++》时的那般震撼,但是也收获不少。把其中的要点记录于下,有些条款加上了自己的理解,权当作读书笔记吧 :-) Item 1: Always Use Properties Instead of Accessible Data Members 这个是地球人都知道的条款了。你需要记住,属性是类的外部接口部分,而(公共)成员却是内部实现。如果把内部实现暴露给外部,对于以后类的实现变更是非常不利的。 Item 2: Prefer readonly to const Item 3: Prefer the is or as Operators to Casts Item 4: Use Conditional Attributes Instead of #if Item 5: Always Provide ToString() //从数据库中挑出所有有效用户
string whereStr = string.Format("where {0} = '1'" ,Customer._IsValid) ; Customer[] customers = (Customer[])DataEntrance.GetObjects(typeof(Customer) ,whereStr) ; ArrayList cusNameList = new ArrayList() ; foreach(Customer cus in customers) { cusNameList.Add(string.Format("{0} {1}" ,cus.ID ,cus.Name)) ; } //绑定 this.comboBox1.DataSource = cusNameList ; 如果为Customer重写ToString()方法, #region ToString
public override string ToString() { return this.ID.ToString() + " " + this.Name.ToString() ; } #endregion 则只需要这样: string whereStr = string.Format("where {0} = '1'" ,Customer._IsValid) ;
Customer[] customers = (Customer[])DataEntrance.GetObjects(typeof(Customer) ,whereStr) ; this.comboBox1.DataSource = customers ; 这样就简便了好多,而且这样做还有一个好处,比如,从ComboBox从选取一个客户时,以前需要这样: string cusID = this.comboBox1.SelectedItem.ToString().Split(' ')[0] ; Customer desCus = null ; foreach(Customer cus in customers) { if(cus.ID = cusID) { desCus = cus ; break ; } } 现在,简单多了,一行代码搞定。 Customer desCus = this.comboBox1.SelectedItem as Customer ; 3月13日 ASP.NET完全入门(14) <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 ASP.NET完全入门(13)下面,我们对上面学到的各种属性进行应用。
例子: 我们首先产生6个Application变量,然后分别用item属性和all属性去逐一取出各个Application变量的内容显示出来。注意为了避免其他公用Application变量的干扰,我们在页面加载时,调用了removeall方法,清空应用的所有公用变量。 1. 程序源代码 <!-- 文件名: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)&" " 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 & " " 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清除。 1. 源程序 <!-- 文件名: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>
效果图:
第五章 安全访问控制
4.5.4 授权用户和角色
GO
<TR> ASP.NET完全入门(12)3. 绑定到表达式:除了使用固定的数据作为数据绑定的数据源以外,asp.net还提供了具有动态表达功能的表达式数据绑定,由于它是根据数据项和常数计算而来,因而提供的数据更加灵活、方便。
例子:书价打折计算,当我们从下拉列表中选择一个折扣率后,会显示出各种书的相应价格。源程序如下: <!-- 文件名:formDataBind03.aspx --> <%@ import namespace="System.Data" %> <%@ import namespace="System.Data.Sql" %> <html> <script language="vb" runat=server> Public CLASS book private _name as string private _price as decimal public readonly property name as string Get return _name end Get end property public readonly property price as decimal Get return _price end Get end Property public sub New(n as string,p as decimal) MyBase.New _name=n _price=p end sub End Class Sub Page_Load(o as object,e as eventargs) if IsPostBack dim values as New ArrayList values.add(New book("红楼梦",100.0)) values.add(New book("三国演义",90.0)) values.add(New book("水浒",85.0)) values.add(New book("西游记",60.0)) lbltxt.text="各种书的价格是:" dg1.datasource=values dg1.Databind end if End Sub Public Function GetRealPrice(price as decimal) dim a as decimal a=CDbl(rate.selecteditem.value) GetRealPrice=price*a End Function </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>数据绑定之表达式绑定</h2> <hr> <form runat=server> 请输入折扣率: <asp:DropDownList id="rate" runat=server> <asp:listitem>1.00</asp:listitem> <asp:listitem>0.95</asp:listitem> <asp:listitem>0.90</asp:listitem> <asp:listitem>0.80</asp:listitem> <asp:listitem>0.70</asp:listitem> <asp:listitem>0.60</asp:listitem> <asp:listitem>0.60</asp:listitem> </asp:DropDownList> <asp:button text="提交" runat=server/> <hr> <asp:label id="lbltxt" runat=server/> <br> <asp:datalist id="dg1" runat=server> <template name="headertemplate"> <table> <tr> <th> 书名 </th> <th> 价格 </th> </tr> </template> <template name="itemtemplate"> <tr> <td> <%# databinder.eval(container.dataitem,"name") %> </td> <td> $<%# GetRealPrice(databinder.eval(container.dataitem,"price")) %> 元 </td> </tr> </template> <template name="footertemplate"> </table> </template> </asp:datalist> </form> </center> </body> </html> 开始时的输出画面: 当我们选择对书价进行九五折后,输出的价格如下: 当我们选择七折时的价格输出如下: 4. 方法绑定:实际上在上一个例子中我们已经见到了使用方法的数据绑定,它利用databinder.eval方法把指定的数据或者是表达式转换成所期望出现的数据类型。DataBinder.Eval含有三个参数,第一个是数据项的容器,对于常用的DataList、DataGrid、Reapter等控件,通常使用Container.DataItem;第二个参数是数据项名;第三个参数是要转换成的数据类型,如果省略就认为是返回该数据项的类型。使用方法绑定的目的通常都是和模板定义相结合产生一些特殊的效果。由于方法绑定比较常见,这里就举一个简单的例子了。 例子:显示待售图书的价格 源程序如下: <!-- 文件名: formDataBind04.aspx--> <html> <script language="vb" runat=server> Public CLASS book private _name as string private _price as decimal public readonly property name as string Get return _name end Get end property public readonly property price as decimal Get return _price end Get end Property public sub New(n as string,p as decimal) MyBase.New _name=n _price=p end sub End Class Sub Page_Load(o as object,e as eventargs) if Not IsPostBack dim ht as New ArrayList ht.add(New book("红楼梦",100.0)) ht.add(New book("三国演义",90.0)) ht.add(New book("水浒",85.0)) ht.add(New book("西游记",60.0)) dl.datasource=ht dl.databind end if End Sub </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>数据绑定之DataBinder.Eval方法</h2> <hr> <form runat=server> <b>图书售价清单</b> <p></p> <asp:datalist id="dl" borderwith="1" girdlines="both" runat=server> <template name="itemtemplate"> 书名:<%# Databinder.eval(container.dataitem,"name") %> 售价:<%# Databinder.eval(container.dataitem,"price") %>元
</template> </asp:datalist> </form> </center> </body> </html> 画面输出结果如下: 3.6.3.1 Repeater控件 正如前面讲到的,Repeater完全是模板驱动的。对同样的DataSource,通过应用不同的模板,你可以得到不同的外观表现。 我们来看看下面的代码: <%@ Page language="C#" src="Repeater1.cs" inherits="Samples.Repeater1Page"%> <asp:Repeater runat=server id="linksListRepeater" DataSource='<%# SiteLinks %>'> <template name="HeaderTemplate"> <ul type="1"> </template> <template name="ItemTemplate"> <li> <asp:HyperLink runat=server Text='<%# DataBinder.Eval(Container.DataItem, "SiteName") %>' NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "SiteURL") %>'> </asp:HyperLink> </li> </template> <template name="FooterTemplate"> </ul> </template> </asp:Repeater> 这个例子显示了通过(<%# … %>)实现数据绑定的语法。这些数据绑定表达式在你调用DataBind的时候得到执行。这里,控件的DataSource是这个页面的DataLinks属性,它是一些URL参考信息。 Repeater控件是唯一允许在Template中使用HTML片断的。本例中,列表被分成三段: l <ul type="1">代表HeaderTemplate; l </ul> 代表FooterTemplate; l 列表的中心内容,是通过<li>来表现的。对SiteLinks集合里的每一个对象重复这个ItemTemplate,就产生了如图的列表内容。 你也可以在HeaderTemplate中使用<table>,在FooterTemplate中使用</Table>,在ItemTemplate中使用<TR>…</TR>。这样你就得到一个表格形式的列表。 你必须指定ItemTemplate。当HeaderTemplate或者FooterTemplate没有被指定时,ItemTemplate将被用作替代。 下面的代码是支持上面代码的: namespace Samples { ... public class Repeater1Page : Page { protected Repeater linksListRepeater; public ICollection SiteLinks { get { ArrayList sites = new ArrayList(); sites.Add(new SiteInfo("Microsoft Home", "http://www.microsoft.com")); sites.Add(new SiteInfo("MSDN Home", "http://msdn.microsoft.com")); sites.Add(new SiteInfo("MSN Homepage", "http://www.msn.com")); sites.Add(new SiteInfo("Hotmail", "http://www.hotmail.com")); return sites; } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (!IsPostBack) { // DataBind the page the first time it is requested. // This recursively calls each control within the page's // control hierarchy. DataBind(); } } } public sealed class SiteInfo { private string siteName; private string siteURL; public SiteInfo(string siteName, string siteURL) { this.siteName = siteName; this.siteURL = siteURL; } public string SiteName { get { return siteName; } } public string SiteURL { get { return siteURL; } } } } Repeater1Page类重载了Page类的OnLoad方法。我们在页面第一次被请求时候,调用DatBind方法。这样,Template里面的每一个数据绑定表达式被计算。由于Repeater可以保存它自身的数据和状态,所以用户提交数据时候,没有必要再次调用DataBind方法(也不需要指定DataSource了)。 页面公开了一个ICollection类型的SiteLinks属性。这个属性被用于指定为Repeater控件的DataSource。前面我们已经知道DataSource必须是ICollection类型的。SiteLinks就是一个简单的ArrayList,里面包含一系列的站点信息。SiteLinks属性被设置为public的,因为只有public和protected的属性在数据绑定表达式中才是可用的。 每一个SiteInfo对象有两个属性:SiteName和SiteURL。在ItemTemplate中,我们通过下面的代码来存取其属性的: <asp:HyperLink runat=server Text='<%# DataBinder.Eval(Container.DataItem, "SiteName") %>' NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "SiteURL") %>'> </asp:HyperLink> 3.6.3.2 DataList控件 DataList 是一个模板控件。通过指定其style属性,可以控制它的表现形式。你还可以使用它的多列属性。 例子 : <%@ Page language="C#" src="DataList1.cs" inherits="Samples.DataList1Page"%> ... <asp:DataList runat=server id="peopleDataList" RepeatColumns="2" RepeatDirection="Vertical" RepeatMode="Table" Width="100%"> <property name="AlternatingItemstyle"> <asp:TableItemstyle BackColor="#EEEEEE"/> </property> <template name="ItemTemplate"> <asp:Panel runat=server font-size="12pt" font-bold="true"> <%# ((Person)Container.DataItem).Name %> </asp:Panel> <asp:Label runat=server Width="20px" Borderstyle="Solid" BorderWidth="1px" BorderColor="Black" BackColor='<%# ((Person)Container.DataItem).FavoriteColor %>'> </asp:Label> <asp:Label runat=server Font-Size="10pt" Text='<%# GetColorName(((Person)Container.DataItem).FavoriteColor) %>'> </asp:Label> </template> </asp:DataList> 通过简单地设置RepeatColumns="2",我们得到了一个多列的DataList。而RepeatDirection=”Vertical”表示:列表将从上到下、然后从左到右显示。而如果你设置成RepeatDirection=” Horizontal”,列表将从左到右、然后从上到下显示。 本例用了DataList的几个style属性。Width属性使列表占用整个窗口宽度,而AlternatingItemstyle属性设置成灰色,使奇数行和偶数行有所区别。 下面的代码是支持这个例子的: namespace Samples { ... public class DataList1Page : Page { protected DataList peopleDataList; protected string GetColorName(Color c) { return TypeDescriptor.GetConverter(typeof(Color)).ConvertToString(c); } private void LoadPeopleList() { // create the datasource Person[] people = new Person[] { new Person("Nikhil Kothari", Color.Green), new Person("Steve Millet", Color.Purple), new Person("Chris Anderson", Color.Blue), new Person("Mike Pope", Color.Orange), new Person("Anthony Moore", Color.Yellow), new Person("Jon Jung", Color.MediumAquamarine), new Person("Susan Warren", Color.SlateBlue), new Person("Izzy Gryko", Color.Red) }; // set the control's datasource peopleDataList.DataSource = people; // and have it build its items using the datasource peopleDataList.DataBind(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (!IsPostBack) { // first request for the page LoadPeopleList(); } } } public sealed class Person { private string name; private Color favoriteColor; public Person(string name, Color favoriteColor) { this.name = name; this.favoriteColor = favoriteColor; } public Color FavoriteColor { get { return favoriteColor; } } public string Name { get { return name; } } } } 例子中,控件的DataSource属性是程序运行时指定的,这和在aspx中声明这些属性形成对照。其实两种方法的效果完全一样,但是,无论你选择哪种方法,你必须调用DataBind,以便控件可以枚举DataSource来创建控件的每一个项目。
本例中的DataSource只是一个由Person对象组成的简单数组。由于数组对象实现了ICollection接口,所以数组可以作为DataSource。本例也显示了不同数据结构和数据类型作为DataSource的可行性和灵活性。 本例显示了如下概念: l 在模板中使用丰富的HTML用户界面 l 使用数组作为DataSource l 编程指定DataSource l 在数据绑定时指定各种表达式 3.6.3.3 DataGrid控件 DataGrid控件可用于创建各种样式的表格。它还支持对项目的选择和操作。下面的几个例子使用了包含如下字段的一个表: title 书名 title ID 编号 Author 作者 Price 价格 Publication date 发行日期 这个表不在数据库中,而是保存在一个名为titlesdb.xml的文件中。我们将逐步给出完整的代码。 首先我们来看看titlesdb.xml的格式: <root> <schema id="DocumentElement" targetNamespace="" xmlns=http://www.w3.org/1999/XMLSchema xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <element name="title"> <complexType content="elementOnly"> <element name="title_id" type="string"></element> <element name="title" type="string"></element> <element name="au_name" type="string"></element> <element name="price" msdata:DataType="System.Currency" minOccurs="0" type="string"></element> <element name="pubdate" type="timeInstant"></element> </complexType> <unique name="titleConstraint" msdata:PrimaryKey="True"> <selector>.</selector> <field>title_id</field> </unique> </element> </schema> <DocumentElement> <title> <title_id>BU1032</title_id> <title>The Busy Executive's Database Guide</title> <au_name>Marjorie Green</au_name> <price>19.99</price> <pubdate>1991-06-12T07:00:00</pubdate> </title> ... </DocumentElement> </root> 在一个典型的web应用中,很可能你需要使用web service或者商业部件来保证最大可能的可扩展性和性能。下面的例子为了简化代码,我们在global.asax中,通过响应application_onstart事件,读取xml数据到一个DataSet,然后缓存这个DataSet到一个Application变量。 代码如下:(global.asax) public void Application_OnStart() { FileStream fs = null; DataSet ds = null; try { fs = new FileStream(Server.MapPath("titlesDB.xml"), FileMode.Open, FileAccess.Read); ds = new DataSet(); // load the data in the xml file into the DataSet ds.ReadXml(fs); } finally { if (fs != null) { fs.Close(); fs = null; } } // cache the dataset into application state for use in individual pages Application["titlesDataSet"] = ds; } 下面的代码产生了一个简单的页面: (dg01.aspx) <%@ Page language="C#" src="DataGrid.cs" inherits="Samples.DataGridPage"%> ... <asp:DataGrid runat=server id="titlesGrid"> </asp:DataGrid> (DataGrid.cs) namespace Samples { ... public class DataGridPage : Page { protected DataGrid titlesGrid; public ICollection GettitlesList() { // Retrieve the list of titles from the DataSet cached in // the application state. DataSet titlesDataSet = (DataSet)Application["titlesDataSet"]; if (titlesDataSet != null) { return titlesDataSet.Tables["title"].DefaultView; } else { return null; } } private void LoadtitlesGrid() { // retrieve the data from the database ICollection titlesList = GettitlesList(); // set the control's datasource titlesGrid.DataSource = titlesList; // and have it build its items using the datasource titlesGrid.DataBind(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (!IsPostBack) { // first request for the page LoadtitlesGrid(); } } } } 这个.cs文件包含了页面的所有代码。在功能上,这些代码和上一节的例子非常相似。通过重载页面的OnLoad方法,获得数据并绑定到DataGrid控件,实现了数据的显示。DataBind方法被调用时,DataGrid控件会根据DataSet的DataTable的每一行,创建表格的每一行。当用户提交表单时,数据绑定不再被调用,控件将根据其原来的状态重新绘制每一个项目。 DataGrid的AutoGenerateColumns属性缺省是True。当AutoGenerateColumns为True 时,DataGrid将检查其数据源和其对象映射,并为每一个共有属性或者字段创建一个列。本例中,DataGrid控件把DataSet中的每一个字段显示为一个列。DataGrid的这种功能使得程序员使用很少的代码就可以使用DataGrid控件。 每一个自动产生的列称为一个BoundColumn(绑定列)。绑定列根据其数据表对应列的数据类型,自动将其转化为一个字符串,显示在表格的一个单元中。 我们来看看改进后的代码: (dg02.aspx) <%@ Page language="C#" src="DataGrid.cs" inherits="Samples.DataGridPage"%> ... <asp:DataGrid runat=server id="titlesGrid" AutoGenerateColumns="false"> <property name="Columns"> <asp:BoundColumn HeaderText="title" DataField="title"/> <asp:BoundColumn HeaderText="Author" DataField="au_name"/> <asp:BoundColumn HeaderText="Date Published" DataField="pubdate"/> <asp:BoundColumn HeaderText="Price" DataField="price"/> </property> </asp:DataGrid> dg02.aspx展示了用户自定义列集合的应用。由于采用了code-behind技术,DataGrid.cs可以不加任何修改。 这里,DataGrid的AutoGenerateColumns设置为false,不允许控件自动创建列集合。这样,DataGrid将应用用户定义的列集合来表现DataSet到一个表格中。 这样做有什么好处呢? l 你可以控制列的顺序。表格的列将按照你给定的顺序排列。而相反地,自动产生的列将按照数据被存取的次序来创建,由于数据被存取的次序是不可指定的,他可能有别于代码中指定的顺序或者数据库中的顺序。 l 每一列的标题都可以指定。这可以通过指定其HeaderText属性来实现。在dg01.aspx中,列的标题缺省为字段名。在很多情况下,这不是你想要的。当然,你还可以使用BoundColumn的其他属性。 l 自动产生的列总是BoundColumn类型。而指定列允许使用继承了BoundColumn的用户控件。 Dg03.aspx是进一步的改进版本,它显示了如何控制DataGrid的外观表现和各个项目的格式化控制。 (dg03.aspx) <%@ Page language="C#" src="DataGrid.cs" inherits="Samples.DataGridPage"%> ... <asp:DataGrid runat=server id="titlesGrid" AutoGenerateColumns="false" Width="80%" BackColor="White" BorderWidth="1px" Borderstyle="Solid" CellPadding="2" CellSpacing="0" BorderColor="Tan" Font-Name="Verdana" Font-Size="8pt"> <property name="Columns"> <asp:BoundColumn HeaderText="title" DataField="title"/> <asp:BoundColumn HeaderText="Author" DataField="au_name"/> <asp:BoundColumn HeaderText="Date Published" DataField="pubdate" DataformatString="{0:MMM yyyy}"/> <asp:BoundColumn HeaderText="Price" DataField="price" DataformatString="{0:c}"> <property name="Itemstyle"> <asp:TableItemstyle HorizontalAlign="Right"/> </property> </asp:BoundColumn> </property> <property name="Headerstyle">
<asp:TableItemstyle BackColor="DarkRed" ForeColor="White" Font-Bold="true"/> </property> <property name="Itemstyle"> <asp:TableItemstyle ForeColor="DarkSlateBlue"/> </property> <property name="AlternatingItemstyle"> <asp:TableItemstyle BackColor="Beige"/> </property> </asp:DataGrid> 和前面的例子一样。不同的是,这里我们对DataGrid的样式属性进行了控制,从而得到了更好的表格外观。和dg02.aspx一样,DataGrid.cs不许要作任何的改进。 由于DataGrid是从WebControl继承来的,所以它也具有Width、BackColor、Borderstyle、Font等样式属性。此外,DataGrid还具有CellPadding等和表格关联的特殊属性。这些属性使程序员可以完全控制DataGrid的样式和表现。 这里还使用了Headerstyle和AlternatingItemstyle,这是和DataGrid项目相关的样式属性。这些属性可以控制表格项目的样式。本例中,表格的偶数行和奇数行具有同样的前景色,但是,偶数行的背景色不同于奇数行。本例还控制了Price一列的样式,使文本靠右对齐。 DataGrid还支持对表格单元的格式化控制。这是通过设置BoundColumn的DataformatString属性来实现的。这样,表格单元的内容将被String.format方法所格式化。如果你不指定DataformatString属性,缺省的ToString方法被调用。 Dg04.aspx显示了如何选择表格的一行: (dg04.aspx) <%@ Page language="C#" src="DataGrid4.cs" inherits="Samples.DataGrid4Page"%> ... <asp:DataGrid runat=server id="titlesGrid" AutoGenerateColumns="false" Width="80%" BackColor="White" BorderWidth="1px" Borderstyle="Solid" CellPadding="2" CellSpacing="0" BorderColor="Tan" Font-Name="Verdana" Font-Size="8pt" DataKeyField="title_id" OnSelectedIndexChanged="OnSelectedIndexChangedtitlesGrid"> <property name="Columns"> <asp:ButtonColumn Text="Select" Command="Select"/> <asp:BoundColumn HeaderText="title" DataField="title"/> <asp:BoundColumn HeaderText="Author" DataField="au_name"/> <asp:BoundColumn HeaderText="Date Published" DataField="pubdate" DataformatString="{0:MMM yyyy}"/> <asp:BoundColumn HeaderText="Price" DataField="price" DataformatString="{0:c}"> <property name="Itemstyle"> <asp:TableItemstyle HorizontalAlign="Right"/> </property> </asp:BoundColumn> </property> <property name="Headerstyle"> <asp:TableItemstyle BackColor="DarkRed" ForeColor="White" Font-Bold="true"/> </property> <property name="Itemstyle"> <asp:TableItemstyle ForeColor="DarkSlateBlue"/> </property> <property name="AlternatingItemstyle"> <asp:TableItemstyle BackColor="Beige"/> </property> <property name="SelectedItemstyle"> <asp:TableItemstyle BackColor="PaleGoldenRod" Font-Bold="true"/> </property> </asp:DataGrid> ... <asp:Label runat=server id="selectionInfoLabel" Font-Name="Verdana" Font-Size="8pt"/> 本例中,DataGrid的SelectedIndexChanged事件被处理,代码封装在下面的.cs文件中。和前面的例子不同,我们增加了一个具有“select”命令的按钮列。这就让DataGrid可以为每一行产生一个选择按钮。同时,SelectedItemstyle属性也被设置,这样可以很清楚地标志当前的选择项目。最后,DataKeyField属性得到指定,这是为了code-behind代码可以使用DataKeys集合。 现在我们来看看code-behind代码: (DataGrid4.cs) namespace Samples { ... public class DataGrid4Page : Page { protected DataGrid titlesGrid; protected Label selectionInfoLabel; public ICollection GettitlesList() { // Retrieve the list of titles from the DataSet cached in // the application state. DataSet titlesDataSet = (DataSet)Application["titlesDataSet"]; if (titlesDataSet != null) { return titlesDataSet.Tables["title"].DefaultView; } else { return null; } } private void LoadtitlesGrid() { // retrieve the data from the database ICollection titlesList = GettitlesList(); // set the control's datasource and reset its selection titlesGrid.DataSource = titlesList; titlesGrid.SelectedIndex = -1; // and have it build its items using the datasource titlesGrid.DataBind(); // update the selected title info UpdateSelectedtitleInfo(); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (!IsPostBack) { // first request for the page LoadtitlesGrid(); } } // Handles the OnSelectedIndexChanged event of the DataGrid protected void OnSelectedIndexChangedtitlesGrid(object sender, EventArgs e) { UpdateSelectedtitleInfo(); } private void UpdateSelectedtitleInfo() { // get the selected index int selIndex = titlesGrid.SelectedIndex; string seltitleID = null; string selectionInfo; if (selIndex != -1) { // display the key field for the selected title seltitleID = (string)titlesGrid.DataKeys[selIndex]; selectionInfo = "ID of selected title: " + seltitleID; } else { selectionInfo = "No title is currently selected."; } selectionInfoLabel.Text = selectionInfo; } } } .cs文件包含了SelectedIndexChanged事件的处理逻辑,和显示当前选择的ID所需要的代码。当用户点击选择按钮时,SelectedIndexChanged事件就被激发。这时,DataGrid的标准命令”Select”被识别,其SelectIndex属性相应改变,然后,OnSelectedIndexChangedtitlesGrid得到执行。 在OnSelectedIndexChangedtitlesGrid函数中,我们调用了UpdateSelectedtitleInfo方法。此方法负责显示当前选择项目的信息,此处为简单地显示ID号。当然,你可以根据这个ID关联的行,从而显示更多的信息。 ID是通过存取DataKeys集合获得的。因为在ASPX中指定了DataKeyField属性,我们可以使用这个集合。典型地,这个字段就是表的主键或者能够唯一确定一行的某个字段。根据这个字段,就可以获得当前选择项目的更具体信息。 本例显示了如何在显示数据之外,实现对数据的选择操作。DataGrid还具有很多其他特性,比如排序、分页、编辑、列模板等等。这里就不详细展开了。 3.6.3.4 Repeater, DataList, or DataGrid? Repeater, DataList, 和DataGrid控件基于同样的编程模型。同时,每个控件又为着不同的目标而设计,所以,选择合适的控件非常重要。 从对象层次图可以看出,Repeater是最轻最小的控件,它仅仅继承了基本控件的功能,包括ID属性、子控件集合等。另一方面,DataList和DataGrid则继承了WebControl功能,包括样式和外观属性。 从对象模型看,repeater是最简单的控件,它也是最小的数据绑定控件,它没有外观,也不表现为任何特定的用户界面。Repeater也支持模板。但它不支持内建的样式和外观属性。如果你需要完全控制页面,用repeater是一个最合适的选择。 DataList具有repeater的功能,并支持外观控制。它继承了WebControl的外观特性,并增加了一些样式属性,以控制其子控件的外观。DataList也支持对项目的标准操作,比如选择、编辑、删除。当需要产生横向或纵向的一系列项目时,采用DataList是最合适的。 DataGrid控件实现了表格样式的列和行。和DataList类似,它也支持外观和样式控制。除了支持对项目的选择、编辑等操作,DataGrid还支持对整个集合的操作,包括分页、排序等等。DataGrid和DataList的最大不同在于,DataGrid不包含任何模板属性,这意味着项目或者表格的行不是模板化的。但是,通过加入TemplateColumn到某个列,你可以在列上使用模板。 下表概括了列表控件的主要功能: 功能 Repeater DataList DataGrid 模板支持 Yes (必须) Yes (必须) 在列中应用 (可选) 表格外观 No No Yes 流式布局 Yes Yes No 列表/报纸样式布局 No Yes No 样式和外观属性 No Yes Yes 项目选择 No Yes Yes 项目编辑 No Yes Yes 删除 No Yes Yes 分页 No No Yes 排序 No No Yes 3.6.4 小结 本章主要讲述了如何把取得的DataSet对象和其他的数据绑定控件相结合,产生我们所期望的页面表现模式的方法。数据绑定控件的使用,不外是首先对DataSource指定数据的来源,然后使用DataBind()方法把数据绑定到控件上。比较麻烦一点的是控件模板的定义,它的使用方法比较灵活,谁也不可能把它一一列举,不过我个人认为基础在于ItemTemplate模板,只要掌握了它,其余的都是细节。 第四篇 应用程序
第一章 什么是应用程序 在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 配置文件的语法规则 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. 4 ASP.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. 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>定义的对象的集合。 ASP.NET完全入门(11)一旦你已经创建了一个存储过程,你就能使用系统存储过程sp_helptext来观看在该存储过程的的SQL语句。比如,如果你输入命令sp_helptext pro_book,就会显示下面的结果:
text …………………………………………… CREATE PROCEDURE pro_book AS SELECT * FROM forum l 注意 你可能感到奇怪的是,sp_helptext系统过程本身就是一种存储过程类型。它是一种系统的存储过程。(系统存储过程存储在Master数据库中,能够被所有的数据库访问。)为了满足你的好奇心,你可以使用命令sp_helptext sp_helptext来观看组成sp_helptext本身的SQL语句。你在创建完存储过程后,不能对其进行修改。假如你需要修改一个存储过程。你必须首先破坏它,然后重新构建之。为了破坏一个存储过程。你可以使用DROP PROCEDURE语句,例如下面的语句删除pro_book存储过程: DROP PROCEDURE pro_book l 注意 你可以使用系统存储过程sp_help来观看在当前数据库中所有存储过程的列表。假如你不加任何修改地执行了sp_help。该过程会显示在当前数据库中所有的存储过程、触发器和表。假如在sp_help后面跟上指定的存储过程,sp_help会仅仅显示那个存储过程的信息。 另外,你也可以使用SQL Enterprise Manager 创建存储过程,在此就不作介绍了。 l 应用 下面我们就用微软的.NET技术来讲述怎么样通过程序来给存储过程传递参数。 首先,我们在数据库NetBBS中建立一个简单的存储过程,代码如下: create procedure pro_book as select * from forum 这是一个最简单的存储过程了,此过程名称为pro_book,是从表forum中选出所有的值。 下面我们就通过程序来调用这个存储过程。我们创建一个文件叫StorePro.aspx,它的代码如下: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) '创建数据集 Dim DS As DataSet '创建数据连接对象 Dim SConn As SQLConnection '创建命令集对象 Dim SComm As SQLDataSetCommand '位数据连接对象咐值 Sconn=New SQLConnection("server=localhost;uid=NetBBS;pwd=;database=NETBBS") SComm = New SQLDataSetCommand("pro_book", SConn) '设置命令对象类型为存储过程 SComm.SelectCommand.CommandType = CommandType.StoredProcedure '建立和填充数据集 DS = new DataSet() SComm.FillDataSet(DS, "forum") SDG.DataSource=DS.Tables("forum").DefaultView SDG.DataBind() End Sub </script> <body> <center> <h3><font face="Verdana">采用存储过程的方式从数据库中调用数据!!</font></h3> <ASP:DataGrid id="SDG" runat="server" Width="360" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#aaaadd" MaintainState="false" /> </center> </body> </html> 大家注意到在程序中有这样的语句: SComm = New SQLDataSetCommand("pro_book", SConn) '设置命令对象类型为存储过程 SComm.SelectCommand.CommandType = CommandType.StoredProcedure 最上面的那句话为在命令中用到的存储过程和数据连接对象,其中pro_book即为我们在数据库NetBBS中创建的存储过程。中间为我们程序的注释;后面的语句为我们设置我们所创建的命令集对象为存储过程。这样,在aspx文件中调用存储过程的过程就完成了。 从上面我们可以看到,在aspx中调用一个存储过程是一件非常简单的事情。下面是程序运行的结果: 由于我们按照表结构的方式把数据从数据库中选取出来,所以我们看到的结果就象是一张表一样,其实我们可以定制我们的输出结果,在后面的章节中我们会详细的介绍这种方法的。 3.4.4.2有返回值 l 从存储过程中获得值 你可以从存储过程中接受值。这些值可以直接在你的aspx文件中使用。同样,你可以在其他的存储过程中获得这些值。假如第一个过程调用了第二个存储过程,则第一个过程能接受有第二个过程设置的参数值。 例如,下面的存储过程输出变量@fname的值: create procedure pro_outbook ( @fid varchar(20), @fname varchar(1000) out ) as select @fname=(select [name] from forum ) 注意在本例子中关键词OUT的使用。该关键词紧跟在参数@fname的定义后面。这指明该参数将会用于从该过程中输出信息。在这个简单的例子中,参数的值将会是根据select语句从表forum中选出的name的集合。 为了这些一个具有输出参数的存储过程,你需要在EXECUTE语句中使用关键词OUT。假如你在一个批处理或者另外一个存储过程中执行该过程时,你必须首先定义一个变量用于存储从过程中传递出的值,如下面的例子所示: DEClARE @pro_results VARCHAR(1000) DEClARE @fid varchar(20) EXECUTE pro_outbook @fid=ƈ',@fname=@pro_results OUT PRINT @pro_results 在该例子中的第一个语句定义了将用于存储从过程pro_outbook中传出的参数值的变量。该变量将和输出参数的数据类型一模一样。第二个语句执行存储过程。注意变量@proc_results后面必须紧跟关键词OUT。最后变量@proc_results的值被打印到屏幕上。 3.4.4.3带输入参数 同样的,我们举一个例子来说明怎样用微软的.NET技术来讲述怎么样通过程序来给存储过程传递参数,并返回程序的结果。 首先,我们在数据库NetBBS中建立一个带有输入参数的存储过程,代码如下: create procedure pro_inputbook @fid varchar(4) as select [id] as 'ID',[name] as '论坛名称',[notes] as '公告',[fatherid] as '父ID',status as '使用状态' from forum where [ID]=@fid 存储过程的名字为pro_inputbook,id和name字段用“[]“括号括起来,只要是这两个字段是 SQL Server中的关键字段。 我们创建一个aspx文件来调用我们的存储过程,下面是我们的文件的代码: (code\database\StoreProWithInPara.aspx) <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> '在页面装载时调用的方法 Sub Page_Load(Src As Object, E As EventArgs) '创建数据集 Dim DS As DataSet '创建数据库连接对象 Dim IConn As SQLConnection '常见命令集对象 Dim IComm As SQLDataSetCommand '给数据库连接对象咐值 IConn=New SQLConnection("server=localhost;uid=NetBBS;pwd=;database=NETBBS") '调用存储过程 IComm = New SQLDataSetCommand("pro_inputbook", IConn) '创建命令集为存储过程! IComm.SelectCommand.CommandType = CommandType.StoredProcedure '向数据库中传递参数 IComm.SelectCommand.Parameters.Add(New SQLParameter("@fid", SQLDataType.NVarChar, 15)) '获得并传递参数 IComm.SelectCommand.Parameters("@fid").value = Request.QueryString("forumid") '填充数据集 DS = new DataSet() IComm.FillDataSet(DS, "forum") '进行数据绑定 IDG.DataSource=DS.Tables("forum").DefaultView IDG.DataBind() End Sub </script> <body style="font: 10pt verdana"> <br><br><br> <center> 有输入参数的存储过程的输出结果: <br><br><br> <ASP:DataGrid id="IDG" runat="server" Width="650" BackColor="#ccccff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#aaaadd" MaintainState="false" /> </center> </body> </html> 我们给程序传递的参数为1,通过连接中传递参数的方式来传递。我们通过 '获得并传递参数 IComm.SelectCommand.Parameters("@fid").value = Request.QueryString("forumid") 这个语句来获得从连接中传来的参数(forumid=1),并通过 '向数据库中传递参数 IComm.SelectCommand.Parameters.Add(New SQLParameter("@fid", SQLDataType.NVarChar, 15)) 这个语句来向存储过程pro_inputbook传递参数,存储过程在接收到参数1后,即把ID=1的数据选择出来,即为我们所显示的结果。 3.4.4.4带输出参数 3.4.4.4.1存储过程 首先我们创建一个带输出参数的存储过程: create procedure pro_outpara @count int output as select @count= (select count(*) from topic) 这是一个很简单的存储过程,它的作用就是计算出所有的文章数出来。 3.4.4.4.1接收程序 正向我们上面说的调用存储过程一样,我们创建的命令集诗一样的: (code\database\StoreProWithOutPara.aspx) IComm = New SQLDataSetCommand("pro_outpara", IConn) IComm.SelectCommand.CommandType = CommandType.StoredProcedure 创建命令集为存储过程方式,在创建数据传送的方式时,就跟上面的不一样了, IComm.SelectCommand.Parameters.Add(New SQLParameter("@title", SQLDataType.Int)) IComm.SelectCommand.Parameters("@title").Direction = ParameterDirection.Output 最后用 System.Math.Ceil(IComm.SelectCommand.Parameters("@count").value)来获得我们的参数的值,具体的程序如下: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) '创建数据连接对象 Dim IConn As SQLConnection '创建命令集对象 Dim IComm As SQLDataSetCommand '创建数据集
Dim DS As DataSet IConn = New SQLConnection("server=localhost;uid=sa;pwd=;database=NETBBS") IComm = New SQLDataSetCommand("pro_outpara", IConn) '创建命令集为存储过程! IComm.SelectCommand.CommandType = CommandType.StoredProcedure '获得并传入参数: IComm.SelectCommand.Parameters.Add(New SQLParameter("@count", SQLDataType.Int)) IComm.SelectCommand.Parameters("@count").Direction = ParameterDirection.Output '填充数据集 DS = new DataSet() IComm.FillDataSet(DS, "topic") '数据绑定 'IDG.DataSource=DS.Tables("topic").DefaultView 'IDG.DataBind() If Not Page.IsPostBack Then TotalPages.Text = System.Math.Ceil(IComm.SelectCommand.Parameters("@count").value) End If End Sub </script> <body bgcolor="#ccccff" style="font: 10pt verdana"> <br><br><br> <center> .NET->有输出参数的存储过程的输出结果: <br><br><br> 文章总数:<asp:Label id="TotalPages" runat="server" /> </center> </body> </html> 运行如下: 3.4.5 表间关系 在通常情况下,不能用一个简单的Grid来显出我们所要的数据,在这种情况下,我们就会有很多种处理方法。我们可以用一个或者几个文件,通过传递参数来实现这个功能。 就用我们的BBS来说,我们想在显示贴子的页面上了解一下发言者的信息,但是我们设计数据库的时候,分别把用户的地址、教育程度、收入等分别存放在不同的表中的,但是他们都有一个ID是共同的,那么我们就可以根据这个ID分别从不同的表中选出用户的地址、教育程度、收入等信息。 又比如我们想在显示贴子的页面上获得论坛ID,之后可以通过传递论坛的ID号来获得论坛信息。至于论坛ID的传送相对接收来说又不同的方法,可以在扁担上传送,也可以在连接上包含参数来传递。至于接收,我们可以用如下语句: Request.QueryString("id") 来实现,在把这个ID传给sql语句,即可选出我们想要的信息。 我们写两个aspx页面来具体讲解如何实现这个表见关系的功能: (code\database\Rel01.aspx)代码如下: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> '在页面装入时用此方法 Sub Page_Load(Src As Object, E As EventArgs) '定义数据集 Dim DS As DataSet '建立数据连接和命令对象 Dim rConn As SQLConnection '设置命令对象 Dim rComm As SQLDataSetCommand '建立数据库的连接 rConn = New SQLConnection("server=localhost;uid=NetBBS;pwd=;database=NETBBS") rComm = New SQLDataSetCommand("select UserID,ForumID AS '论坛ID', title as '贴子标题 ',contents as '贴子内容',nView as '浏览人数',nreply as '回复人数' from topic", rConn) '填充数据集 DS = new DataSet() rComm.FillDataSet(ds, "topic") '打包 rDG.DataSource=ds.Tables("topic").DefaultView rDG.DataBind() End Sub </script> <title> Relation!!! </title> <body style="font: 10pt verdana"> <center> <br> <form runat="server"> <h3><font face="Verdana">.NET->表间关系!</font></h3> <span id="Message" MaintainState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="rDG" runat="server" Width="800" BackColor="#ffffff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#aaaadd" DataField="UserID" > <property name="Columns"> <asp:HyperLinkColumn DataNavigateUrlField="UserID" DataNavigateUrlformatString="Rel02.aspx?id={0}" Text="用户信息" /> </property> </ASP:DataGrid> </form> </center> </body> </html> (code\database\Rel02.aspx)文件中的接收参数的方法跟上面我们说的一样,我们的sql语句相对简单,但是即使对复杂的sql语句,他们的方法都是一样的,下面来看看我们的第二个文件的代码: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> '在页面装入时用此方法 Sub Page_Load(Src As Object, E As EventArgs) '定义数据集 Dim DS As DataSet '建立数据连接和命令对象 Dim rConn As SQLConnection '设置命令对象 Dim rComm As SQLDataSetCommand Dim SelectCmd As String = "select [ID],education, area, salary from [user] where [ID]=@uid" '建立数据库的连接 rConn = New SQLConnection("server=localhost;uid=NetBBS;pwd=;database=NETBBS") rComm = New SQLDataSetCommand(SelectCmd, rConn) '获得纪录的ID号码 rComm.SelectCommand.Parameters.Add(New SQLParameter("@uid", SQLDataType.VarChar, 11)) rComm.SelectCommand.Parameters("@uid").value = Request.QueryString("id") '填充数据集 DS = new DataSet() rComm.FillDataSet(ds, "user") '打包 rDG.DataSource=ds.Tables("user").DefaultView rDG.DataBind() End Sub </script> <title> Relation!!! </title> <center> <body style="font: 10pt verdana"> <form runat="server"> <h3><font face="Verdana">.NET->表间关系!</font></h3> <h4><font face="Verdana">用户:<%=Request.QueryString("id")%> 的详细信息</font></h4> <ASP:DataGrid id="rDG" runat="server" Width="800" BackColor="#ffffff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#ffffff" /> </form> </center> </body> </html> 点击用户信息连接,我们会卡到下面的结果: 3.4.6 事务处理 事务控制或者事务管理,是指关系型数据库管理系统执行数据库事务的能力。事务是最基本的工作单元,事务中的sql语句必须按照逻辑次序执行,并且要就是成功的执行整个工作单元的操作,要么就一点也不执行。 比如有一个表area,保存用户的家庭地址,在同一时间内,由两个用户同时对着一个表进行操作,一个用户的操作是: select * from area 另外一个是: update area(address) values(“深圳市福田区园岭西路”) 则第一个用户选出来的地址是原来数据苦中存在的地址,还是更新后的地址呢?结果显示,在select过程中出现修改,则原来的信息是无效的。 在sql server 中,创建事务的语句是: begin {transaction │ tran}[transaction_name] 由于我们这本书不是专门介绍sql server的,所以在此就不涉及得太多了,大家有兴趣可以 参考其他有关书籍。 我们现在这个例子就是在用户插入数据之前有一个查询,我们应用数据库的事务处理控制方法,在查询操作结束之前,禁止数据的插入。 3.4.7 小结 本章介绍了如何以ADO.NET编程方式来实现数据库的常用操作。我们重点介绍了记录的增加、删除和修改,以及目前比较流行的在数据库端使用存储过程的方法。另外我们还介绍了数据库表间的关系描述以及重要应用的事物处理方法。 第五章 Dataset的用法
Dataset 并不是Recordset的简单翻版。从一定的意义上来说,DataView更类似于Recordset。如果说DataReader是访问数据的最容易的方式,那么Dataset则是最完整的数据访问对象。通过Dataset,你可以操作已有的数据,还可以通过程序创建Dataset,加入Table到Dataset,并建立这些Table之间的关系。 3.5.1 使用Dataset的几个步骤 第1步,创建到数据源的连接: SQLConnection con =new SQLConnection("server=localhost;uid=sa;pwd=;database=pubs"); 第2步,创建DataSetCommand对象,指定一个存储过程的名字或者一个SQL语句,指定数据链路; SQLDataSetCommand cmd =new SQLDataSetCommand("SELECT * FROM Authors", con); 第3步,创建一个Dataset对象 DataSet ds = new DataSet(); 第4步,调用DataSetCommand的FillData方法,为Dataset填充数据。注意:数据链路没有必要是打开的。如果数据链路是关闭状态,FillData函数会打开它,并在FillData之后关闭数据链路。如果数据链路本来就是打开的,在FillData之后,数据链路依然保持打开状态。 int iRowCount = cmd.FillDataSet(ds, “Authors”); 第5步,操作数据。由于FillData返回了记录的个数,我们可以构造一个循环,来操纵Dataset中的数据。 for(int i=0; i< iRowCount; i++){ DataRow dr = ds.Tables[0].Rows; Console.WriteLine(dr["au_lname"]); } 3.5.2 小结 本章主要介绍了如何从远程数据库取得数据到本地DataSet中的方法步骤。 第六章 数据绑定技术 本文介绍ASP.NET的Repeater,DataList,and DataGrid 服务器端控件。这些控件将数据集合表现为基于HTML的界面。本文还引入了利用这些控件的几个例子。 3.6.1 简介 Repeater、DataList 、DataGrid控件是System.Web.UI.WebControls名空间(Namespace)里几个相关的页面组件。这些控件把绑定到它们的数据通过HTML表现出来,它们又被成为“列表绑定控件”(list-bound controls)。 和其他Web组件一样,这些组件不仅提供了一个一致的编程模型,而且封装了与浏览器版本相关的HTML逻辑。这种特点使得程序员可以针对这个对象模型编程,而无须考虑各种浏览器版本的差别和不一致性。 这三个控件具有把它们的相关数据“翻译”成各种外观的能力。这些外观包括表格、多列列表、或者任何的HTML流。同时,它们也允许你创建任意的显示效果。除此之外,它们还封装了处理提交数据、状态管理、事件激发的功能。最后,它们还提供了各种级别的标准操作,包括选择、编辑、分页、排序等等。利用这些控件,你可以轻松地完成如下的Web应用:报表、购物推车、产品列表、查询结果显示、导航菜单等等。 下面我们进一步讲解这些控件,其基本使用方法和如何选用它们。 3.6.2 列表绑定控件是如何工作 下面我们来看看列表绑定控件的属性和方法,从而一窥其内在工作机理。 3.6.2.1 DataSource属性 Repeater、DataList、DataGrid都是从System.Collections.Icollection继承来的,所以都带有DataSource属性。DataSource,最简单地讲,就是一组相同特征的对象或者一个相同对象的集合。 在ASP.NET 框架里,有许多对象都有DataSource属性。包括System.Data.DataView和ArrayList、HashTable等等。 和其他传统的需要ADO Recordset的数据绑定控件不同,这些列表绑定控件只需要实现其ICollection接口,而不必一定指定其DataSource属性。而且,由于其DataSource属性允许为很多数据类型和数据结构,从而使这些对象的引用更加简单和灵活。 例子1:下面我们以从服务器的SQL Server数据库pubs中取出作者信息,作为 三种控件Repeater、DataList、DataGrid的数据源为例,来说明以数据视图(DataView)作为数据源(DataSource)的方式。 设计如下:在画面的上部有一选择列表(DropDownList)。当用户从中选取一种控件来显示数据时,它会根据选择,把隐藏在下部的3个画板之一显示出来。 1.以数据视图作为数据源方式的源程序 <!-- 文件名:code\database\formDataSource.aspx --> <!-- 文件名:formDataSource.aspx --> <%@ import namespace="system.data" %> <%@ import namespace="system.data.sql" %> <!--DataSet 要引用system.data,数据库连接要用到system.data.sql--> <html> <script language="vb" runat=server> sub Page_Load(o as object,e as eventargs) dim MyConnection as SQLConnection dim MyStr as String dim MyDataSetCommand as SQLDataSetCommand dim MyDataSet as New DataSet If Not IsPostBack MyConnection=New SQLConnection("server=localhost;uid=sa;pwd=;database=pubs") '指定连接的服务器、用户、口令、数据库 MyStr="Select au_lname,au_fname from authors" '要得到的数据为author表中的姓氏和名字 MyDataSetCommand=New SQLDataSetCommand(Mystr,MyConnection) MyDataSetCommand.FillDataSet(MyDataSet,"Authors") '从数据库中取得数据放入内存DataSet对象中,并映射为Authors表 Session("MyDs")=MyDataSet '保存DataSet对象于连接变量MyDs中 Else MyDataSet=Session("MyDs") '取出DataSet对象 if MyDataSet is Nothing Response.Write("无法取得数据") else '根据选择列表的选择,绑定数据,并显示相应的画板 Select Case DpDnLst.SelectedItem.text case "Repeater" Response.write _ ("<center>以<I>Repeater</I>控件显示数据</center>") db1.datasource=MyDataSet.tables("authors").defaultview db1.databind panel1.visible=True panel2.visible=False panel3.visible=False case "DataList" Response.write _ ("<center>以<B>DataList</B>控件显示数据</center>") db2.datasource=MyDataSet.tables("authors").defaultview db2.databind panel1.visible=False panel2.visible=True panel3.visible=False case "DataGrid" Response.write _ ("<center>以<U>DataGrid</U>控件显示数据</center>") db3.datasource=MyDataSet.tables("authors").defaultview db3.databind panel1.visible=False panel2.visible=False panel3.visible=True case else End Select end if End If end sub </script> <head> <title> 数据绑定技术试验 </title> </head> <body bgcolor=#ffffff> <center> <h2>DataSource试验</h2> <hr> <form runat=server> 请选择控件类型: <asp:DropDownList id="DpDnLst" runat=server> <asp:Listitem>Repeater</asp:Listitem> <asp:Listitem>DataList</asp:Listitem> <asp:Listitem>DataGrid</asp:Listitem> </asp:DropDownList> <asp:button text="提交" runat=server/> <hr> <!--定义三个画板,根据下拉列表的选择,使指定的画板可见--> <!-- 画板一 :定义一个Repeater控件 --> <asp:panel id="panel1" visible=false runat=server> <asp:repeater id="db1" runat=server> <!--定义Repeater控件显示的表头 --> <template name="headertemplate"> <table> <tr> <td> 姓氏 </td> <td> 名字 </td> </tr> </template> <!--定义Repeater控件数据显示的格式 --> <template name="itemtemplate"> <tr> <td> <%# databinder.eval(container.dataitem,"au_lname") %> </td> <td> <%# databinder.eval(container.dataitem,"au_fname") %> </td> </tr> </template> <!--定义Repeator控件显示的表尾 --> <template name="footertemplate"> </table> </template> </asp:repeater> </asp:panel> <!-- 画板二:定义一个DataList控件 --> <asp:panel id="panel2" visible=false runat=server> <asp:datalist id="db2" runat=server> <!--定义datalist的显示格式为:姓氏----名字 --> <template name="itemtemplate"> <%# databinder.eval(container.dataitem,"au_lname") %> ---- <%# databinder.eval(container.dataitem,"au_fname") %> <br> </template> </asp:datalist> </asp:panel> <!-- 画板三:定义一个DataGrid控件 --> <asp:panel id="panel3" visible=false runat=server> <asp:datagrid id="db3" runat=server> </asp:datagrid> </asp:panel> </form> </center> </body> </html> 2.开始时的输出画面: 3.当选择以Repeater控件显示后的输出画面: 4.当选择以DataList控件显示后的输出画面: 5.当选择以DataGrid控件方式显示后的输出画面: 例子2:下面举一个简单的例子演示用ArrayList作为数据源的情况,因为三种控件(Repeater控件、DataList控件、DataGrid控件)关于数据源数据的取得方法是一样的,虽然最终的表现形式并不一样,为了节省篇幅,我们只以DataGrid控件作为输出。 为和例子1比较,我们也以输出上述名字为例,但由于是演示,只取了前5人的姓名。 1. 以数组列(ArrayList)作为数据源的源程序 <!-- 文件名:formDataSource01.aspx --> <html> <script language="vb" runat=server> '定义一个类用于保存姓名 Public Class PName private first_name as String private last_name as String Public Property Fname as String Get return first_name End Get Set first_name=value End Set End Property Public Property Lname as String Get return last_name End Get Set last_name=value End Set End Property '创建实例 Public Sub New(f as String,l as String) MyBase.New first_name=f last_name=l End Sub End Class Sub Page_Load(o as object,e as eventargs) If Not IsPostBack '第一次请求时初始化一个姓名数组,然后绑定到datagrid上 dim values as New ArrayList values.add(New PName("Bennet","Abraham")) values.add(New PName("Blotchet-Halls","Reginald")) values.add(New PName("Carson","Cheryl")) values.add(New PName("DeFrance","Michel")) values.add(New PName("del Castillo","Innes")) dtgrd.datasource=values dtgrd.databind End If End Sub </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>数据绑定之数据源试验(ArrayList)</h2> <hr> <form runat=server> <asp:DataGrid id="DtGrd" runat=server/> </form> </center> </body> </html> 2. 程序运行后的输出结果: 例子3:下面的例子将演示如何使用HashTable作为列表控件的数据源的使用方法,它基本上和ArrayList的用法类似,只是在添加时要有索引如:MyHashTable.add(index,object),index为hash表的关键字,object为具体的内容;用它作数据源时,要用它的values属性而并不是其本身,如:MyDataGrid.DataSource=MyHashTable.values。 1. 用HashTable作为数据源例子的源程序 <!-- 文件名: formDataSoure02.aspx --> <html> <script language="vb" runat=server> '定义一个类用于保存姓名 Public Class PName private first_name as String private last_name as String Public Property Fname as String Get return first_name End Get Set first_name=value End Set End Property Public Property Lname as String Get return last_name End Get Set last_name=value End Set End Property '创建实例 Public Sub New(f as String,l as String) MyBase.New first_name=f last_name=l End Sub End Class Sub Page_Load(o as object,e as eventargs) dim ht as New HashTable if Not IsPostBack 'hash Table 的Add方法所带参数为:索引,对象 ht.add("1",New PName("Bennet","Abraham")) ht.add("2",New PName("Blotchet-Halls","Reginald")) ht.add("3",New PName("Carson","Cheryl")) ht.add("4",New PName("DeFrance","Michel")) ht.add("5",New PName("del Castillo","Innes")) DtGrd.datasource=ht.values DtGrd.databind '数据绑定到hashtable上 End if End Sub </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>数据绑定之数据源试验(HashTable)</h2> <hr> <form runat=server> <asp:DataGrid id="DtGrd" runat=server/> </form> </center> </body> </html> 2. 使用HashTable作为数据源的输出结果画面: 例子4:最后我们以实现Icolletion接口方式来实现数据源的绑定,在下面的例子中我们用一个函数LoadData返回了一个Icolletion对象,实际上在LoadData函数内部,我们可以使用上面提到的几种产生数据源的方法来构造LoadData函数。 1. 用Icolletion对象来作为数据源的例子的源程序:
<!-- 文件名:formDataSource03.aspx --> <%@ Import NameSpace="System.Data" %> <html> <script language="vb" runat=server> Function LoadData() As ICollection Dim dt As DataTable Dim dr As DataRow '建立数据表 dt = New DataTable dt.Columns.Add(New DataColumn("姓氏", GetType(String))) dt.Columns.Add(New DataColumn("名字", GetType(String))) '载入五个人的数据 dr = dt.NewRow() dr(0) = "Bennet" dr(1) = "Abraham" dt.Rows.Add(dr) dr = dt.NewRow() dr(0) = "Blotchet-Halls" dr(1) = "Reginald" dt.Rows.Add(dr) dr = dt.NewRow() dr(0) = "Carson" dr(1) = "Cheryl" dt.Rows.Add(dr) dr = dt.NewRow() dr(0) = "DeFrance" dr(1) = "Michel" dt.Rows.Add(dr) dr = dt.NewRow() dr(0) = "del Castillo" dr(1) = "Innes" dt.Rows.Add(dr) '返回数据表的数据视图 LoadData = New DataView(dt) End Function Sub Page_Load(o as object,e as eventargs) If Not IsPostBack DtGrd.DataSource=LoadData DtGrd.DataBind End If End Sub </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>数据绑定之数据源试验(ICollection)</h2> <hr> <form runat=server> <asp:DataGrid id="DtGrd" runat=server/> </form> </center> </body> </html> 2.使用Icollection对象作为数据源的画面输出: 3.6.2.2 Items集合 每一个列表绑定控件都有一个Items集合,集合中的每一个Item是DataSource所指定的一个对象。 下表列示的是和DataSource指定数据相关联的Item类型 Item 缺省类型的一个Item AlternatingItem Items集合中奇数编号的一个Item SelectedItem 当前选中的Item EditItem 当前编辑的Item 下面列示的是和DataSource指定数据无关的Item类型 Header 用于表达列表表头 Footer 用于表达列表表尾 Separator 用于表达两个Item之间的内容。只适用于Repeater和DataList Pager 用于分页显示数据集合。适用于DataGrid控件。 3.6.2.3 数据绑定和Item集合的创建 列表绑定控件基于ASP.NET框架,需要你明确地进行数据绑定。这就意味着:只有当DataBind方法被调用时,才真正需要轮询其DataSource所代表的数据。 当DataBind方法被调用时,列表绑定控件将轮询DataSource,创建Items集合,并从DataSource取回数据,以初始化Items集合。如果状态管理被激活,这些控件将自动保存所需要的信息,当用户提交数据时,不再需要你指定DataSource属性。 明确的DataBind调用使你可以准确地决定什么时候DataSource是需要准备好的,同时也减少了和数据库的交互,从而提高了WEB应用的性能。 一般的规则是:当你需要重建所有的Items时候,你需要调用DataBind。大多数情况下,你只需要在页面第一次被请求的时候,调用DataBind。在以后的页面运行中,你只需要在相应的事件中,比如引起Items集合变化的事件,或者和数据源关联的查询条件发生了变化,或者数据将从只读模式改变到编辑模式,这时候就需要调用DataBind方法。 3.6.2.4 style属性 通过使用对象模型的style属性,你可以定义整个DataList或者DataGrid的外观。这些属性允许你指定字体、颜色、边框以及其表现风格。这些控件自身的属性,包括ForeColor、BackColor、Font和Borderstyle,将影响整个控件的表现风格。 另外,对于控件包含的每个Item,通过指定Itemstyle、AlternatingItemstyle、Headerstyle,也可以控制相应Item的外观表现。对于DataGrid,你还可以控制到每个列的每个单元,只需要指定Headerstyle、Footerstyle和Itemstyle。 3.6.2.5 Template模板 style控制列表绑定控件的可见格式,而template则定义了内容和每个Item的表现。你可以把Template想象成一小段HTML代码,通过它决定了如何把每个Item显示给用户。 Repeater和DataList通过你指定的模板来工作,这些模板包括ItemTemplate、AlternatingItemTemplate、HeaderTemplate。 DataGrid控件不使用模板。但是,在此控件的Columns集合里使用TemplateColumns是可以的,而且TemplateColumns里的每一个TemplateColumn都可以包含一个模板,就象Repeater和DataList里的一样。这样你也可以定制每一个DataGrid的表现形式。 3.6.3 模板里的数据绑定 一个模板Template定义了一个Item所包含的控件结构。使用数据绑定表达式,这个结构里的控件属性可以绑定到和这个Item关联的数据属性。 Item从逻辑上来看,是相应Template的父亲,可以通过“Container”来引用。每个Container都有DataItem属性,所以在构造Template的每个数据绑定表达式时候,Container.DataItem常常出现。这些我们从后面的例子里也可以学习到。 数据绑定的方式大概有四种:属性绑定、集合绑定、表达式绑定以及方法绑定。 1. 属性绑定: 是指ASP.Net的数据绑定可以绑定到公共的变量、页面的属性乃至其他服务器端控件的属性上。但是应该注意的是,这些属性、公用变量一定要在使用DataBind()方法以前初始化,否则可能导致不可预知的错误。 例子:在页面中定义一个字符串变量和一个整型变量,一个字符串属性和一个整型属性,以及一个不可见的TextBox 控件,然后在页面加载的时候,调用页面的DataBind方法,看数据是否绑定成功。 源程序如下: <!-- 文件名:code\database\bonder\formDataBind01.aspx --> <!-- 文件名:formDataBind01.aspx --> <html> <script language="vb" runat=server> Public PubVar as New String("公用变量") Public PubInt as Integer=2222 Sub Page_Load(o as object,e as eventargs) DataBind End Sub Public ReadOnly Property PubPropStr as String Get Return "页面字符串属性" End Get End Property Public ReadOnly Property PubPropInt as Integer Get Return 1111 End Get End Property </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ffffff> <center> <h2>数据绑定到属性试验</h2> <asp:TextBox id="tb" text="TextBox控件属性" visible=False runat=server/> <hr> </center> <form runat=server> 数据1:(<%# PubVar %>)<br> 数据2:(<%# PubInt %>)<br> 属性1:(<%# PubPropStr %>)<br> 属性2:(<%# PubPropInt %>)<br> 控件1:(<%# tb.text %>) </form> </body> </html> 执行后的页面输出画面如下: 2. 集合绑定: 作为数据源的还可以是集合对象,在asp.net中只要是支持Icollection接口的集合对象都可以作为列表服务器端控件。最常见的,我们使用数组(ArrayList)、哈希表(HashTable)、数据视图(DataView)、数据读写器(DataReader)等集合作为列表服务器端控件的数据源。 例子:以显示一个下拉列表(dropdownlist)为例,说明作为数据源的4种集合对象(ArrayList、DataView、HashTable、DataReader)进行数据绑定时的用法。 为了达到相同的输出效果,下拉列表的选项都为我国六个城市。 ArrayList的用法最简单,首先生成一个ArrayList的对象,然后用Add方法把城市加入,最后绑定到DropDownList控件即可。代码架构如下: Dim values as New ArrayList values.add(“…”) … DropDownList1.DataSource=values DropDownList1.DataBind … HashTable用法和ArryList的用法查不多,但是有两点值得注意。一是当使用Add 方法向HashTable中添加数据时,它比ArryList要多出一个关键值字段,语法为Add(keyvalue,Object);二是,设置DataSource属性值时,不是以HashTable,而是以其values值作为数据源,其代码框架如下: Dim ht as HashTable Ht=New HashTable Ht.add(Keyvalue,”…”) ‘注意Keyvalue为键值 … DropDownList1.DataSource=ht.values DropDownList1.DataBind … DataView方式绑定,首先应该得到一个数据视图(DataView),而得到数据视图的方式可以是从远端数据库中取得,或者是本地动态定义Table,添加数据得到;然后把得到的数据视图赋予DataSource属性,同时指定DatavalueField属性,指定DatavalueField属性实际上就是指明DropDownList控件到底使用数据视图中的哪一个字段作为自己的数据源。下面的代码示例,使用本地定义方式来产生数据视图,当然可以使用SQL取数据方式,示例代码框架如下: Dim dt as DataTable Dim dr as DataRow Dt=New DataTable Dt.Columns.add(New DataColumn(“…”,GetTypeString(…)) ‘产生数据表所需要的字段 … dr=dt.NewRow dr(0)=… dr(1)=… … dt.rows.add(dr) ‘产生一条记录加入到数据表中 … DropDownList1.DataSource=New DataView(dt) DropDownList1.DatavalueField=… DropDownList1.DataBind … ‘以下为SQL方式 <%@ Import NameSpace=”System..Data” %> <%@ Import NameSpace=”System..Data.SQL” %> … dim MyConn as SQLConnectoin dim MyStr as String dim MyDataSetCommand as SQLDataSetCommand dim MyDataSet as DataSet MyConn=new SQLConnection(“server=…;uid=…;sa=…;dataserver=…”) ‘设立连接数据库的字符串 MyStr=”Select * from …” ‘查询数据语句 MyDataSetCommand=New SQLDataSetCommand(MyStr,MyConn) ‘定义取数据命令 MyDataSetCommand.FillDataSet(MyDataSet,”…”) ‘把远地取得的DataSet以…名字放入内存DataSet … DropDownList1.DataSource=MyDataSet.tables(…).Defaultaview DropDownList1.DatavalueField=… DropDownList1.DataBind … 最后DataReader方式实际上和DataView差不多,区别在于DataReader是以流方式取得数据,而DataView可以从内存中取得,所以DataReader方式在数据绑定以前必须打开连接链路,完成绑定之后再关闭链路,当数据量较大时,这种方式可能会有问题。代码框架如下: dim MyConn as SQLConnection dim Mystr as String dim MyComm as SQLCommand dim MyReader as SQLDataReader MyConn=New SQLConnection("server=…;uid=…;pwd=…;database=…") '连接数据库的字符串 MyStr="select * from …" ‘查询字符串 MyComm=New SQLCommand(Mystr,MyConn) ‘要执行的命令串 MyConn.Open ‘打开通往服务器的链路 MyComm.Execute(MyReader) ‘执行查询语句 DropDownList1.Datasource=MyReader DropDownList1.DatavalueField=… DropDownList1.DataBind MyConn.Close ‘绑定完毕才能执行数据链路的关闭 下面的代码示例中,使用了服务器上的SQL数据库test中的一个关于城市名的表city,我们再使用前,应先在数据库服务器上建立test数据库,并建立一个城市名表city,它至少含有一个city_name的字段,为便于比较4种不同的实现方法可以达到相同的效果,建议加载的试验数据为相同的城市名,整个例子的完整代码如下: <!-- 文件名: formDataBind02.aspx --> <%@ import NameSpace="System.Data" %> <%@ import NameSpace="System.Data.SQL" %> <html> <script language="vb" runat=server> Sub Page_Load(o as object,e as eventargs) If Not IsPostBack '首次加载,以四种方式绑定数据源 Dim values as ArrayList values=New ArrayList() values.add("北京") values.add("上海") values.add("天津") values.add("重庆") values.add("香港") values.add("澳门") lstArray.datasource=values lstArray.databind '控件以ArrayList方式绑定 Dim dt as DataTable Dim dr as DataRow Dim i as Integer Dim ar as Array dt=New DataTable() dt.Columns.add(New DataColumn("City",GetType(string))) '建立一个city字段 For i =0 to 5 dr=dt.NewRow() dr(0)=values.item(i) dt.rows.add(dr) Next '添加六个城市的数据 lstDataView.DataSource=New DataView(dt) lstDataView.DatavalueField="City" lstDataView.DataBind '控件以DataView方式绑定 Dim ht as HashTable ht=New HashTable() ht.add("1","北京") ht.add("2","上海") ht.add("3","天津") ht.add("4","重庆") ht.add("5","香港") ht.add("6","澳门") lstHash.DataSource=ht.values lstHash.DataBind '控件以HashTable方式绑定 dim MyConn as SQLConnection dim Mystr as String dim MyComm as SQLCommand dim MyReader as SQLDataReader MyConn=New SQLConnection("server=localhost;uid=sa;pwd=;database=test") '连接服务器上的Test数据库 MyStr="select city_name from city" '从city表中取城市名字段(city_name) MyComm=New SQLCommand(Mystr,MyConn) MyConn.Open MyComm.Execute(MyReader) lstDR.Datasource=MyReader lstDR.DatavalueField="city_name" lstDR.DataBind MyConn.Close End If End Sub </script> <head> <title> 数据绑定试验 </title> </head> <body bgcolor=#ccccff> <center> <h2>数据绑定之集合绑定试验</h2> <hr> <form runat=server> <b>绑定到ArrayList的效果:</b> <asp:dropdownlist id="lstArray" runat=server /> <b>绑定到DataView的效果:</b> <asp:dropdownlist id="lstDataView" runat=server /> <br> <p></p> <b>绑定到HashTable的效果:</b> <asp:dropdownlist id="lstHash" runat=server /> <b>绑定到DataReader的效果:</b> <asp:dropdownlist id="lstDR" runat=server /> </form> </center> </body> </html> ASP.NET完全入门(10)3.3.2.4 三种方法的对比
一般来说,这三种存取数据库的方法中,SQL Managed Provider效率最高,其次是ADO.NET Managed Provider+OLEDB,最差的是ADO.NET Managed Provider+ODBC。下面是在普通PIII微机上,对于Access 2000和MS SQL Server 2000上的测试结果: 数据库连接类型 页面显示所需时间(秒) ADO.NET Managed Provider+ODBC 0.831195 ADO.NET Managed Provider+OLEDB 0.100144 SQL Managed Provider 0.060086 3.3.2.5测试程序 (122303.aspx) <%@ Page EnableSessionState="False" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <%@ Import Namespace="System.Data.SQL" %> <script language="VB" runat="server"> Sub Refresh(ByVal sender As System.Object, ByVal e As System.EventArgs) Dim d1,d2 As DateTime Dim strConn if Page.IsValid then d1=Now() Dim iChoice As Integer=CInt(Choices.SelectedItem.value) select case iChoice case 1 strConn="DSN=pubs;" ADOBindData(strConn) case 2 strConn="Provider=SQLOLEDB.1;Data Source=(local);uid=sa;pwd=;Initial Catalog=pubs" ADOBindData(strConn) case 3 strConn="server=localhost;uid=sa;pwd=;Database=pubs" '"server=localhost;uid=sa;pwd=;database=northwind;" SQLBindData(strConn) Case Else end select d2=Now() result.Text = "用时(Ticks):"&d2.Ticks-d1.Ticks end if End Sub Sub ADOBindData(strConn) '设置连接串... '创建对象ADOConnection Dim objConn as ADOConnection = New ADOConnection(strConn) objConn.Open() '打开数据链路 '创建SQL字符串 Dim strSQL as String = "SELECT * FROM authors" '创建对象ADODatasetCommand 和Dataset Dim objDSCommand as ADODatasetCommand Dim objDataset as Dataset = New Dataset objDSCommand = New ADODatasetCommand(strSQL, objConn) '填充数据到Dataset '并将数据集合命名为 "Author Information" objDSCommand.FillDataSet(objDataset, "Author Information") objConn.Close() '关闭数据链路 objConn = Nothing '清除对象 Authors.DataSource = _ objDataset.Tables("Author Information").DefaultView Authors.DataBind() End Sub Sub SQLBindData(strConn) '设置连接串... '创建对象ADOConnection Dim objConn as SQLConnection = New SQLConnection(strConn) objConn.Open() '打开数据链路 '创建SQL字符串 Dim strSQL as String = "SELECT * FROM authors" '创建对象SQLDatasetCommand 和Dataset Dim objDSCommand as SQLDatasetCommand Dim objDataset as Dataset = New Dataset objDSCommand = New SQLDatasetCommand(strSQL, objConn) '填充数据到Dataset '并将数据集合命名为 "Author Information" objDSCommand.FillDataSet(objDataset, "Author Information") objConn.Close() '关闭数据链路 objConn = Nothing '清除对象 Authors.DataSource = _ objDataset.Tables("Author Information").DefaultView Authors.DataBind() End Sub </script> <HTML> <BODY> <H2>测试设置</H2> <form Action="122303.aspx" Method="Post" RunAt="Server"> <asp:RadioButtonList ID="choices" RunAt="Server"> <asp:ListItem selected Text="ADO.NET Managed Provider+ODBC" value=1/><br> <asp:ListItem Text="ADO.NET Managed Provider+OLEDB" value=2/><br> <asp:ListItem Text="SQL Managed Provider" value=3/> </asp:RadioButtonList> <br> <asp:LinkButton runat="server" onClick="Refresh" Text="开始测试"/> <br> <H2>测试结果</H2> <asp:label id="result" RunAt="Server" Text="No result"/> <br> <H2>测试数据</H2> <asp:DataGrid id="Authors" runat="server"/> </form> </BODY> </HTML> 3.3.3使用DataSets
使用DataSets有两种方式,一是从数据库中得到,一是自己编程动态创建一个DataSets。 使用从数据库端得到的DataSets方式主要是为了方便用户在客户端操作修改远端的数据库管理系统中的相应信息。而使用编程创建DataSets,是由于DataSets的数据事先并不知道,需要在程序运行中得到数据并填充进DataSets。采用DataSets作为本地数据来源中心的好处是,应用逻辑一样的程序就与数据来源不同分开,当数据源发生变化时,就只需要修改填充DataSets的程序而不用修改应用程序。 3.3.3.1从数据库得到DataSets的使用 使用一个从数据库获得的DataSets较为复杂,它的步骤大概如下: 1. 使用SQLDataSetCommand命令(SQL方式)或者ADODataSetCommand命令(ADO方式)从数据库管理系统中获取一个表结构及其数据填充到本地内存的DataSet的一个表中。 例如: ·Ado方式 Dim MyDsComm As New ADODataSetCommand Dim MyComm As ADOCommand Dim MyConn As ADOConnection MyConn = New ADOConnection _ ("Provider=SQLOLEDB.1;Initial Catalog=Northwind;" & _ "Data Source=(local);User ID=sa;") MyComm = New ADOCommand("SELECT * FROM Customers", MyConn) MyDsComm.SelectCommand = MyComm ·SQL方式 Dim MyConn as SQLConnection Dim MyComm as SQLDataSetCommand Dim MyDs as New DataSet MyConn=New SQLConnection(“server=localhost;uid=sa;pwd=;database=pubs”) MyComm=New SQLDataSetCommand(“Select * from authoers”,MyConn) MyComm.FillDataSet(Myds,”authers”) 2.对DataSet中的表对象DataTable的数据进行操作,包括增加、删除、修改它的DataRow对象 3.使用GetChanges方法产生一个DataSet修改后的对象的DataSet集合。 代码如下: Dim changedDataSet As DataSet changedDataSet = ds.GetChanges(DataRowState.Modified) 4.通过对产生的DataSet对象的HasErrors属性的监控,查看是否DataSet中的表有错误发生。 5.如果有错误发生,就要对DataSet中的各个表进行错误检查,方法一样,也是根据各个DataTable的HasErrors属性。如果表中有错误发生,那么GetErrors方法就会被激活,并且会返回一个含有错误的DataRow对象的数组。 6.当表出错时,对于每一个DataRow对象的RowError属性进行检测。 7.如果可能,处理发生的错误。 8.使用DataSet对象的Merge方法把检测无错误发生的修改后的DataSet合并入原先的DataSet中,代码如下: ds.Merge(changedDataSet) 9.使用DataSetCommand对象的update方法,把合并后的DataSet对象送往数据库端进行修改,代码如下: MyDataSetCommand.Update(ds) 10.使用DataSet对象的AcceptChanges方法对数据库修改进行确认,或者使用RejectChanges方法撤消对数据库的修改,代码如下: Ds.AcceptChanges 3.3.3.2编程实现DataSet 1.使用DataSet()创建器创立一个DataSet对象。 DataSet()可以跟一个字符串用以指明创建的DataSet名字 Dim ds1 as New DataSet Dim ds2 as New DataSet(“MyDataSet”) 2.增加一个DataTable到DataSet中。 具体操作是,首先在DataSet对象的Tables集合中,增加一个表 ds.Tables.Add(New DataTable(表名)) 然后,再在该表中的Columns集合中增加相应的列 ds.Tables(表名).Columns.Add(列名,列类型) 例如:我们在ds对象中建立一个订购表(Order),它有三个字段,客户名(CUNM)、订货编号(ORNO)、订货数量(ORNM) ds.Tables.Add(New DataTable(“Order”)) ds.Tables(“Order”).Columns.Add(“CUNM”,GetType(String)) ds.Tables(“Order”).Columns.Add(“ORNO”,GetType(String)) ds.Tables(“Order”).Columns.Add(“ORNM”,GetType(int32)) ds.Tables(“Order”).PrimaryKey= New DataColumn(ds.Tables(“Order”).Columns(“ORNO”) 在上面的例子中,我们还设置了订购表的键值,这是通过对它的PrimaryKey的属性设置来得到的,设置键值的好处在于可以防止相同记录的输入,保证数据的唯一性。 3.设置表间的关系 由于DataSet对象中可以含有多个DataTable,而事实上每一个表又不可能与其他的表没有任何的关系,这样就带来了一个问题,我们如何描述两个不同的表之间的关系?asp.net提供了DataRelation对象来描述表和表之间的关系。DataRelation对象至少需要两个参数才能确定两个表之间的关系,这是因为在两个表的关系中,至少需要一个主键列和一个外键列,才能确定两者之间的对应关系。 例如:关于客户购物有两个表,一个是客户信息表(Customer),一个是购物信息表(Order),很显然它们两者之间存在着某种联系。经过分析,我们发现客户编号(CUNO)在两个表中都存在,它使我们能够把两个表的信息连接起来,告诉我们这样一个事实,谁订购了什么物品。因此需要建立关于客户信息表和购物信息表的一个联系,用Asp.net语言表达如下: Dim ds as DataSet … ds.Relations.Add(“CustomerOrder”,ds.Tables(“Customer”).Columns(“CUNO”), ds.Tables(“Order”).Columns(“CUNO”)) 4.在关系表间的浏览 通过DataRelaiton的设置,我们可以在同一个DataSet中,由对一个表操作,找到可能引起的相关表的变化。例如,对于客户信息表中的对应于某个人的一条记录,我们可以在购货信息表中找到所有属于他的购货信息,演示代码如下: dim orderRows() as DataRow orderRows=ds.Tables(“Customer”).ChildRelations(“CustomerOrder”).GetChildRows( ds.Tables(“Customer”).Rows(0)) 5.数据约束的使用 在关系数据库中,使用数据约束的目的是为了使数据库的一致性得到保证。当数据发生改变时,数据约束被执行,用以检查对数据的修改,是否和已经定义的规则相符合,如果不符合修改将不能生效。在asp.net中提供了两种数据约束,ForeignKeyConstraint和UniqueConstraint。 ForeignKeyConstraint,外键值一致性约束,定义当表中的一条记录被删除或者是增加一条记录时,与该表相关的其他表的相应记录如何处理。例如,当一个客户被人从客户信息表中删去,那么在购物信息表中的关于他的购物信息的记录如何处理等等。 ForeignKeyConstraint有五个可能的值如下: ·Cascade 当表中记录被删除或者更新以后,对应表中的记录相应被删除和更新 ·SetNull 当表中记录被删除或者更新以后,对应表中的记录被置为Null ·SetDefault 当表中记录被删除或者更新以后,对应表中的记录被置为缺省值 ·None 当表中记录被删除或者更新以后,对应表中的记录不做任何处理 ·Default 当表中记录被删除或者更新以后,ForeignKeyConstraint采用其缺省值,通常该值为Cascade 具体使用ForeigKeyConstraint时,首先应创建它,然后设置DeleteRule和UpDateRule属性,指明当删除和更新记录时,对应表的处理规则。 例子:我们对客户信息表定义一个外键定义,它定义当客户信息表中记录删除时,其关联表—购物信息表中的数据也应删除(意味着用户不存在,自然也不应该有他的购物信息),当客户信息表中记录被修改时,购物信息置为缺省的特殊值(意味着,当销售人员发生差错,记错购物用户,那么以他的名义购物的定单不应算在该用户头上,置为特殊标记,以供今后修改),代码演示如下: dim fk as New ForeignKeyConstraint(ds.Tables(“Customer”).Columns(“CUNO”), ds.Tables(“Order”.Columns(“CUNO”)) ‘创建外键约束为Customer表和Order表中CUNO字段 fk.DeleteRule=Cascade fk.UpdateRule=SetDefault ‘删除规则为Cascade,修改规则为SetDefault ds.Tables(“Customer”).Constraints.Add(fk) ‘加入Customer表的一致性约束集合中 UniqueConstraint,唯一性约束,它指定了数据表中的一个列或者几个列的集合的值的唯一性,通常被指定为唯一约束的字段都是表的键值。 例如:对于客户信息表,因为每个人的购物都必须和别人区别,这样才能保证正确地付款和发送货物,因而每一个人的客户编号都不应该相同,这时就可以使用唯一性约束来保证客户信息表中的客户编号唯一。演示代码如下: dim uc as UniqueConstraint uc=New UniqueConstraint(ds.Tables(“Customer”).Columns(“CUNO”)) ‘指定唯一约束为Customer表中的CUNO字段 ds.Tables(“Customer”).Constraints.Add(uc) ‘把唯一约束加入Customer表的约束中 6.处理DataSet的事件 为了便于用户对DataSet的控制,asp.net提供了DataSet的一系列可被用户处理的事件,它们包括: ·PropertyChange 当属性发生改变时 ·MergeFailed DataSet合并失败时 ·RemoveTable 删除一个表时 ·RemoveRelation 删除一个关系时 ·Adding the event handler to the event 增加一个事件处理函数时 例如: ds.AddOnPropertyChange(new System.ComponentModel.PropertyChangeEventHandler _ (AddressOf me.DataSetPropertyChange)) ‘指定当DataSet发生PropertyChange事件时的消息处理函数为DataSetPropertyChange ds.AddOnMergeFailed(new System.Data.MergeFailedEventHandler _ (AddressOf me.DataSetMergeFailed)) ‘指定当DataSet发生MergeFailed事件时的消息处理函数为DataSetMergeFailed ‘当PropertyChange发生时的处理函数 Private Sub DataSetPropertyChange _ (ByVal sender As Object, ByVal e As System.PropertyChangeEventArgs) … End Sub ‘当MergeFailed发生时的处理函数 Private Sub DataSetMergeFailed _ (ByVal sender As Object, ByVal e As System.Data.MergeFaileedEventArgs) … End Sub 3.3.3.3使用DataTable DataTable是DataSet中一个对象,它与数据库表的概念基本一致,简单起见,你就可以把它认成是数据库DataSet中的表。 1. 创建一个DataTable
DataTable创建器跟使用DataSets创建器差不多,可以跟一个参数,用以指定表名。 例如: dim MyTable as DataTable MyTable = New DataTable("Test") MyTable.CaseSensitive = False MyTable.MinimumCapacity = 100 其中CaseSensitive属性指定是否区分大小写,这里指定不区分,CaseSensitive属性是否打开对于查找、排序、过滤等操作有很大的影响。MinimumCapacity属性指定创建时保留给数据表的最小记录空间。另外还有一个TableName的属性,它指定数据表的名称,例如下面两种方式创建的表是一样的。 1) dim MyTable as DataTable MyTable=New DataTable(“test”) 2) dim MyTable as New DataTable MyTable.TableName=”test” 2. 创建表列 一个DataTable又含有一个表列(Columns)的集合。表列的集合形成了表的数据结构,就如同数据库概念中,字段对应于表一样。我们可以使用Columns集合的Add方法向表中添加表列。该方法带有两个参数,一个是表列名,一个是该列的数据类型。由于我们通常在定义表列时,是使用.net构架中的数据类型,而非数据库的数据类型,所以需要使用GetType方法把.net架构的数据类型转换成数据库中的数据类型。 例如:我们建立一个客户信息表(Customer),它含有三个字段: 用户姓名(CUNM) 字符型 客户编号(CUNO) 字符型 用户序号(IDNO) 整型 Dim MyTable as DataTable Dim MyColumn as DataColumn MyTable = new DataTable("Customer") MyColumn = MyTable.Columns.Add("CUNM",GetType("String") ) MyColumn = MyTable.Columns.Add("CUNO",GetType("String") ) MyColumn = MyTable.Columns.Add("IDNO",GetType("int32") ) 3. 创建表达式列 asp.net甚至允许创建一些依赖于其他表达式的表列,这样做的好处是,体现了表列之间的某种自然的联系。 要创建表达式表列,首先要指定表列的DataType属性,它表明了表达式运算结果的数据类型;然后设置表列的Expression属性为所需的表达式。 例如:一个很明显的例子是利息税,它为总金额*税率*0.2。在同一表中总金额为total列,税率为rate列,利息税为tax列。它们的关系如下: Dim tax As DataColumn = New DataColumn tax.DataType = GetType("Currency") tax.Expression = "total *rate*0.20" 也可以: MyTable.Columns.Add(“tax”,GetType(“Currency”),”total*rate*0.20) 4. 使用自增列 在一些数据库中,我们会发现有这样一种数据类型,通常称作系统序号,当我们向表中增加一条记录时,该字段会自动累加,以后我们可以通过这一唯一序号来标识每一条记录。在asp.net中,同样也可以实现类似的功能,这就是自增表列的使用。 定义自增表列实际上是对DataColumn对象的三个属性:AutoIncrement、AutoIncrementSeed、AutoIncrementStep的使用。 AutoIncrement属性,指定是否打开自增功能。 AutoIncrementSeed属性,指定自增的起始值。 AutoIncrementStep属性,指定自增的步长。 例如: dim MyTable as New DataTable dim MyColumn as DataColumn MyColumn=MyTable.Columns.Add(“Sqno”,GetType(“int32”)) MyColumn.AutoIncrement=True ‘打开自增功能 MyColumn.AutoIncrementSeed=0 ‘自增从0值起始 MyColumn.AutoIncrementStep=2 ‘每次增长2 5. 建立主键值 通常在一个表中,我们会定义一个主键,它能够唯一标识该表中的每一条记录。主键可以为表中的一个表列,也可以为几个表列的集合。主键不能为空,而且不能重复,我们可以用DataColumn的两个属性AllowNull和Unique来实现(DataColumn1.AllowNull=False DataColumn1.Unique=True)。最后DataTable对象的PrimaryKey属性指定主键。 例如: dim MyColumn as DataColumn dim MyTable as DataTable … MyColumn=MyTable.Columns(“CUNO”) MyColumn.AllowNull=False MyColumn.Unique=True MyTable.PrimaryKey=MyColumn 当键值为几个表列的集合时: dim MyColumn as DataColumn() MyColumn(0)=MyTable.Columns(“col1”) MyColumn(1)=MyTable.Columns(“col2”) … MyTable.PrimaryKey=MyColumn 3.3.3.4数据的载入 l 向表中加入数据 当一个表结构已经创建好以后,剩下的问题就是如何把数据载入我们已经建立好的表中。通常采用的方法是,先创建一个DataRow对象,它类似于数据库概念中的记录,然后对DataRow的Columns集合进行赋值,最后把DataRow对象加入到DataTable的DataRows集合中,就相当于在表中插入一条记录。 例如:如下一个表MyTable中有两个列Sqno和Name,Sqno为序号,Name设为”MyName”+序号,我们利用一个循环产生n条记录到MyTable中 Dim i as integer Dim n as integer Dim MyRow as DataRow … For i = 0 to n MyRow = MyTable.NewRow() ‘产生一条新记录 MyRow("Sqno") = I ‘对sqno字段赋值 MyRow("Name") = "MyName" & i.ToString() ‘对name字段赋值 MyTable.Rows.Add(MyRow) ‘加入记录到表中 Next … l 删除表中记录 DataTable的Rows集合提供了两种方法从一个数据表中删除一条记录,它们是Remove方法和Delete方法。示例如下: 删除MyTable中的第三条记录: MyTable.Rows.Remove(3)或者 MyTable.Rows(3).Delete Delete方法和Remove方法的区别不仅仅是方法的使用形式上。当调用Remove方法后,那么指定的DataRow就会从Rows集合中被删除。而Delete方法调用时,指定的DataRow并不真正从Rows集合中删除,只是作了一个删除标记,直到DataSet对象调用AcceptChanges方法的时候,才真正被删除;如果是RejectChanges方法被调用,那么Delete方法删除的DataRow对象将被恢复。 l 使用表中的数据 对于DataTable中的每一个Row,它都可能有三种状态:Original、Current、Preposed。Original状态是指当数据第一次被加入到数据表中时候的状态。Current态指经过多次改变Original数据后得到的Row。Preposed态存在于一个相当短暂的时期,它是由original态过渡到Current态时的中间状态,一个明显的例子是对数据进行修改而尚未完成时,开始是Original态,完成后是Current态,而这之间就是Preposed态。 为了说明对表中数据的使用,我们来看下面一个例子,它是对workTable按每一个字段进行遍历,并把字段名和内容显示出来。 Dim CurrRows() As DataRow = workTable.Select(Nothing, Nothing, _ System.Data.DataViewRowState.CurrentRows) ‘对workTable数据集合选择有效的DataRows放入CurrRows数组 Dim list As String = System.String.Empty ‘清空list字符串 Dim RowNo As Integer Dim ColNo As Integer For RowNo = 0 to CurrRows.Count – 1 ‘每一条记录的循环 For ColNo = 0 To workTable.Columns.Count – 1 ‘一条记录中每一个字段的循环 list = "" list &= workTable.Columns(colNo).ColumnName & " = " & _ CurrRows(RowNo)(ColNo).ToString Console.WriteLine(list) Next Next If CurrRows.Count < 1 Then Console.WriteLine("No CurrentRows Found") 从上面的例子我们可以看出,对Rows集合使用DataTable的Select方法可以找出有效的Rows集合,然后根据Rows.count和columns.count可以确定有效的记录数和字段数,最后利用记录索引值和列索引值可以唯一确定数据表中的任何数据。 3.3.4 DataReader的使用方法 3.3.4.1Read方法 熟悉Recordset的读者一定在想,如何对一个Dataset中的每一个记录进行操作呢?这就不得不提到ADO.NET的DataReader对象了。我们来看看下面的例子: <%@import namespace="system.data.SQL"%> <script language="vb" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) Dim sqlText as String = "select * from authors" Dim cnString as string = "server=localhost;uid=sa;pwd=;database=pubs;" Dim dbRead AS SQLDataReader Dim sqlCmd AS SQLCommand sqlCmd = New SQLCommand(sqlText,cnString) sqlCmd.ActiveConnection.Open() sqlCmd.execute(dbread) while dbRead.Read() response.write("<br>" & dbRead.Item("au_lname")) End while End Sub </script> 还记得Recordset的MoveNext和Recordset的EOF吗?为了对Recordset的每一条记录进行操作,我们需要首先调用其MoveNext方法移动记录,然后判断是否已经到了记录集合的末尾。 在ADO.NET中,一切变得更加简单了。DataReder的Read方法自动移动记录到下一条,并返回移动是否成功的信息。相信使用过Iterator对象的读者一定很喜欢这样的操作方法吧。 另外,上面的代码中,我们并没有显式创建SQLConnection对象。我们把连接字符串传递给SQLCommand,通过sqlCmd.ActiveConnection.Open()创建了到数据库的链路。 3.3.4.2更复杂的Read
下面代码演示了利用DataReader生成两个下拉列表的的情况。 <%@import namespace="system.data.SQL"%> <SCRIPT LANGUAGE="vb" RUNAT="server"> Sub Page_Load(myList AS Object,E as EventArgs) If Not Page.IsPostBack() Dim dbRead AS SQLDataReader Dim dbComm AS SQLCommand Dim strConn AS String Dim SQL AS String strConn = "server=sql.database.com;uid=fooman;password=foopwd;" SQL = "Select * from Color ORDER BY Color" dbComm = New SQLCommand(SQL,strConn) dbComm.ActiveConnection.Open() dbComm.execute(dbRead) While dbRead.Read() ShirtColorOptions.items.add(New ListItem(dbRead.Item("Color"))) End While SQL = "Select * from Size ORDER BY Size" dbComm = New SQLCommand(SQL,strConn) dbComm.ActiveConnection.Open() dbComm.execute(dbRead) While dbRead.Read() ShirtSizeOptions.items.add(New ListItem(dbRead.Item("Size"))) End While End IF End Sub </SCRIPT> <form RUNAT="server" method="get"> <asp:DropDownList id="shirtColorOptions" runat="server" DataTextField = "URL"/> <asp:DropDownList id="shirtSizeOptions" runat="server" DataTextField = "Size"/> </form> 执行结果: 3.3.4.3把DataReader绑定到DataGrid 下面的例子是基于NET Framework Beta2的。 <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <% Dim myConn As SQLConnection = new SQLConnection("server=localhost;uid=sa;pwd=;database=NorthWind;") Dim myCommand As SQLCommand = new SQLCommand("select * from cusotmers",myConn) myConn.Open() cusotmers.DataSource = myCommand.Execute() cusotmers.DataBind() myConn.Close() %> <HTML> <BODY> <asp:DataGrid id="cusotmers" runat="server"/> </BODY> </HTML> 3.3.4.4利用DataReader插入记录 <SCRIPT LANGUAGE="vb" RUNAT="server"> Sub showDb() <%@import namespace="system.data.SQL"%> Dim dbRead AS SQLDataReader Dim dbComm AS SQLCommand Dim strConn AS String Dim strSQL AS String strConn= "server=my.sql.database;uid=fooname;password=foofoo;" strSQL = "INSERT INTO myDatabase (dbvalue1) valueS('the thing')" dbComm = New SQLCommand(strSQL, strConn) dbComm.ActiveConnection.Open() dbComm.execute(dbRead) End Sub </SCRIPT> 3.3.5 小结 本章对在ADO.NET中如何和远端数据库相连作了进一步的阐述。和数据库相连,ADO.NET提供了三种方式,1)通过ODBC相连 2)通过OLEDB相连 3)直接和SQL Server相连。三种方式由于应用层次的差异,效率由低到高,独立性由高到低。对于相连数据库的数据处理,也有两种方式。一种是通过DataSet来隔离异构的数据源,另一种是以流方式从数据源读取(DataReader方式)。 第四章 ADO.NET数据库基本操作 3.4.1 插入记录 怎么向数据库插入记录?下面归纳了几种方法。 3.4.1.1通过SQLCommand 插入一条记录到数据库的SQL语句格式为: Insert Into 表名 (字段1,字段2,。。。) values (值1,值2,。。。) 我们知道,SQLCommand 可以执行SQL命令,我们把插入记录的SQL语句传递到SQLCommand的CommandText属性,然后执行其ExecuteNonQuery方法,就可以了。 Dim strConn As String Dim strComm As String Dim oConn As SQLConnection Dim oComm As SQLCommand strConn = "server=localhost;uid=sa;pwd=;database=northwind" strComm = "INSERT INTO CUSTOMERS (CustomerId, CompanyName, Contactname, Contacttitle, Address) values ('DarkMan','Sino-ASP.COM', 'Mr. Li', 'CTO','不要找我')" oConn = new SQLConnection(strConn) oComm = new SQLCommand(strComm, oConn) Try oConn.Open() ‘执行命令 oComm.ExecuteNonQuery() Catch myException as Exception //出错处理 Finally oConn.Close() End Try 3.4.1.2通过SQLDataSetCommand 如果需要批量插入记录,可以使用SQLDataSetCommand。下面是一个示例: Dim strConn,strComm As String //数据库连接字符串 strConn="server=localhost;uid=sa;pwd=;database=northwind" //查询语句 strComm="select * from region" Dim oConn As New SQLConnection(strConn) Dim oDSComm As New SQLDataSetCommand(strComm,oConn) Dim oParam As SQLParameter oDSComm.InsertCommand = new SQLCommand("Insert into Region (RegionID, RegionDescription) valueS (@RegionID, @RegionDescription)", oConn) oParam = oDSComm.InsertCommand.Parameters.Add(new SQLParameter("@RegionID", SQLDataType.Int)) oParam.SourceVersion = DataRowVersion.Current oParam.SourceColumn = "RegionID" oParam = oDSComm.InsertCommand.Parameters.Add(new SQLParameter("@RegionDescription", SQLDataType.NChar, 50)) oParam.SourceVersion = DataRowVersion.Current oParam.SourceColumn = "RegionDescription" Dim oDS as New DataSet ‘取回RegionID oDSComm.MissingSchemaAction = MissingSchemaAction.AddWithKey oDSComm.FillDataSet(oDS, "Region") Dim index Dim oRow as DataRow for index=0 to 20 oRow = oDS.Tables("Region").NewRow() oRow (0) = CStr(index) oRow (1) = "地区"+CStr(index) oDS.Tables("Region").Rows.Add(newRow) next Try oDSComm.Update(oDS,"region") Catch oException As Exception //错误处理 Finally oConn.close End Try 3.4.2 修改记录 对数据库中的数据进行修改的sql 语句时非常简单的,如用: UPDATE FORUM SET Notes=’大家好啊!!’ where [ID]=1 这个语句即可把表FORUM 中ID=1的字段Notes的值改为“大加好啊!!”,这些大家应该很熟悉的了。但是不知大家在 .NET中用此语句来操作数据库应用的如何? 下面就是我们具体的应用,我们创建一个aspx文件来具体时间一下。我们这个简单的程序具有编辑、更新、取消更新的功能。下面是我们的文件代码: (code\database\UpDate.aspx) <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> '建立数据连接和命令对象 Dim UConn As SQLConnection '在页面装入时用此方法 Sub Page_Load(Sender As Object, E As EventArgs) '建立与数据库的连接 UConn = New SQLConnection("server=localhost;uid=NetBBS;pwd=;database=NETBBS") If Not (IsPostBack) BindGrid() End If End Sub '在点击Edit连接时用到此方法: Sub UDG_Edit(Sender As Object, E As DataGridCommandEventArgs) UDG.EditItemIndex = CInt(E.Item.ItemIndex) BindGrid() End Sub '在点击Cancle连接时用到此方法: Sub UDG_Cancel(Sender As Object, E As DataGridCommandEventArgs) UDG.EditItemIndex = -1 BindGrid() End Sub '在点击UpDate连接时用到此方法:
Sub UDG_Update(Sender As Object, E As DataGridCommandEventArgs) '创建数据集 Dim DS As DataSet '创建命令对象 Dim UComm As SQLCommand '定义修改数据的sql语句 Dim UpdateCmd As String = "UPDATE FORUM SET [ID]=@fid,[Name]=@fname,Notes=@Notes,FatherID=@FatherID,status=@status where [ID]=@fid" '设置命令对象类型 UComm = New SQLCommand(UpdateCmd, UConn) '获得更改的数据 UComm.Parameters.Add(New SQLParameter("@fid", SQLDataType.VarChar, 4)) UComm.Parameters.Add(New SQLParameter("@fname", SQLDataType.VarChar, 50)) UComm.Parameters.Add(New SQLParameter("@Notes", SQLDataType.VarChar, 500)) UComm.Parameters.Add(New SQLParameter("@FatherID", SQLDataType.VarChar, 4)) UComm.Parameters.Add(New SQLParameter("@status", SQLDataType.VarChar, 1)) ' Dim Cols As String() = {"@fid","@fname","@Notes","@FatherID","@status"} '激活数据连接 UComm.ActiveConnection.Open() Try '执行命令集 UComm.ExecuteNonQuery() Message.InnerHtml = "修改成功!!" '改为Edit连接 UDG.EditItemIndex = -1 '处理异常 Catch Exp As SQLException If Exp.Number = 2627 Message.InnerHtml = "相同的记录在数据库中" Else Message.InnerHtml = "不能更改纪录!!" End If Message.style("color") = "red" End Try '关闭数据连接 UComm.ActiveConnection.Close() '调用BindGrid()方法 BindGrid() End Sub '定义BindGrid()方法 Sub BindGrid() Dim DS As DataSet Dim UComm As SQLDataSetCommand '从表forum选出数据 UComm = new SQLDataSetCommand("select * from forum", UConn) '填充数据集 DS = new DataSet() UComm.FillDataSet(DS, "forum") '数据的绑定 UDG.DataSource=DS.Tables("forum").DefaultView UDG.DataBind() End Sub </script> <title> Update! </title> <body style="font: 10pt verdana"> <BR> <CENTER> <form runat="server"> <h3><font face="Verdana">.NET->修改纪录</font></h3> <span id="Message" MaintainState="false" style="font: arial 11pt;" runat="server"/><p> <!--响应对数据库操作的模板--> <ASP:DataGrid id="UDG" runat="server" Width="800" BackColor="#ffffff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#ffffff" OnEditCommand="UDG_Edit" OnCancelCommand="UDG_Cancel" OnUpdateCommand="UDG_Update" > <property name="Columns"> <asp:EditCommandColumn EditText="编辑" CancelText="取消" UpdateText="修改" Itemstyle-Wrap="false"/> </property> </ASP:DataGrid> </form> </CENTER> </body> </html> 首先出来的页面是显示从数据库选择出来的数据,带有编辑的连接,为如下的结果: 然后我们点击“编辑“连接,进入编辑页面,如下: 更改其中的数据,之后点击“修改”,发现我们的数据已经修改了: 3.4.3 删除记录 删除一个记录跟更改纪录差不多,删除一条数据库NetBBS中表forum中的击卢克用下面的语句: delete from forum where [id]=11 这个语句把id=11的数据删除掉。 我们在aspx文件中实现这个目的,sql语句已经没有问题了,成下的事情就是获得要删除纪录的ID号码。在数据库中,我们定义的表forum的ID号码为一个主键,我们用下面的语句来获得她:
'获得要删除的纪录的ID号码 SComm.Parameters.Add(New SQLParameter("@fid", SQLDataType.VarChar, 4)) SComm.Parameters("@fid").value = SDG。DataKeys(CInt(E.Item.ItemIndex)) 获得ID之后,我们就把此ID号传给sql语句来执行: Try SComm.ExecuteNonQuery() Message.InnerHtml = "删除成功!" & DeleteCmd Catch Exp As SQLException Message.InnerHtml = "不能删除纪录!" Message.style("color") = "red" End Try SComm.ExecuteNonQuery()即为执行命令集的语句,成功和失败个返回不同的值。完整的代码如下(code\database\del.aspx): <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> '建立数据连接和命令对象 Dim SConn As SQLConnection '在页面装入时用此方法 Sub Page_Load(Src As Object, E As EventArgs) '建立数据库的连接 SConn = New SQLConnection("server=localhost;uid=NetBBS;pwd=;database=NETBBS") If Not (IsPostBack) BindGrid() End If End Sub '删除纪录的方法: Sub SDel(Sender As Object, E As DataGridCommandEventArgs) '设置命令对象 Dim SComm As SQLCommand Dim DeleteCmd As String = "DELETE from FORUM where [ID] = @fid" SComm = New SQLCommand(DeleteCmd, SConn) '获得要删除的纪录的ID号码 SComm.Parameters.Add(New SQLParameter("@fid", SQLDataType.VarChar, 4)) SComm.Parameters("@fid").value = SDG.DataKeys(CInt(E.Item.ItemIndex)) '激活数据连接 SComm.ActiveConnection.Open() Try SComm.ExecuteNonQuery() Message.InnerHtml = "删除成功!" & DeleteCmd Catch Exp As SQLException Message.InnerHtml = "不能删除纪录!" Message.style("color") = "red" End Try '关闭数据连接! SComm.ActiveConnection.Close() BindGrid() End Sub '数据绑定方法: Sub BindGrid() '定义数据集 Dim DS As DataSet Dim SComm As SQLDataSetCommand SComm = New SQLDataSetCommand("select * from FORUM", SConn) '填充数据集 DS = new DataSet() SComm.FillDataSet(DS, "FORUM") '打包 SDG.DataSource=DS.Tables("FORUM").DefaultView SDG.DataBind() End Sub </script> <title> Delete!! <title> <body style="font: 10pt verdana"> <br><br><br> <center> <form runat="server"> <h3><font face="Verdana">.NET->删除数据纪录!</font></h3><br><br> <span id="Message" MaintainState="false" style="font: arial 11pt;" runat="server"/><p> <ASP:DataGrid id="SDG" runat="server" Width="800" BackColor="#ffffff" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#ffffff" DataKeyField="ID" OnDeleteCommand="SDel" > <property name="Columns"> <asp:ButtonColumn Text="删除数据" CommandName="Delete"/> </property> </ASP:DataGrid> </form> </center> </body> </html> 点击ID=12的删除数据连接,结果如下: 我们可以看到该数据已经被我们删除,同时在页面上打印出删除成功的信息,并把该sql语句给打印出来了。 3.4.4 存储过程 在SQL Server中存储过程是和传统的计算机应用程序最相近的事物,并具有如下的优点: 假如你有一套复杂的SQL语句需要在多个aspx文件中执行。你可以把他们放入一个存储过程,然后执行该存储过程。这能够减少你aspx文件的大小。同时还能确保在每一页上执行的SQL语句都相同。当你执行一个SQL的批处理时。服务器首先必须编译在批处理中的所有语句。这不但需要时间,还要花费服务器资源。相比较而言,在存储过程第一次执行后,它就不需要重新编译了。通过使用存储过程,你可以跨过编译这一步,更快地执行SQL语句集合。从一个动态页中执行一个存储过程比执行一个SQL语句的集合更有效。 你可以对存储过程输入输出值。这意味着存储过程非常的灵活,相同的存储过程可以根据不同的输入值返回不同的信息。 当你向数据库服务器传递一个SQL语句集合时,必须传递其中的每一个独立语句,而当你执行存储过程时,相反的,仅仅传递一个简单的语句。通过使用存储过程,你可以减少在网络上的阻塞。 你可以配置表的权限,比如用户只能通过使用存储过程来修改表。这就能增加在你数据库中表的安全性。你可以在其他的存储过程内部执行你的存储过程。这种策略就允许你在非常小的存储过程上建立非常复杂的存储过程。这也意味着你可以为许多不同的编程任务使用相同的存储过程。 当你在动态页中添加SQL语句时,你必须仔细考虑能否把这些语句放置到存储过程中。上面提到的优点都是实质性的。如下一部分所示,存储过程是非常容易创建的。 3.4.4.1创建存储过程 l 使用CREATE PROCEDURE创建存储过程 你可以使用CREATE PROCEDURE来创建一个存储过程。下面就是一个非常简单的存储过程的一个例子: CREATE PROCEDURE pro_book AS SELECT * FROM forum 当你创建存储过程时,你必须给它指定一个名称。在本例子中,存储过程的名称为pro_book。你可以给存储过程赋予任何你想要的名称,但最好你能够使该名称在一定程度上描述存储过程的功能。每一个存储过程都包括一个或多个SQL语句。为了指明是存储过程一部分的SQL语句,你只需简单地在关键词AS后面包含它们。在前面例子中的存储过程只包含一个SQL语句。当该存储过程执行时,它返回在forum表中所有的记录。 你可以使用EXECUTE语句来执行一个存储过程。比如,为了执行pro_book存储过程,你可以使用如下的语句: EXECUTE pro_book 当你执行该存储过程时,所有包括在其中的SQL语句都会执行,在上面的例子中,会返回所有在forum表中的记录。 当在批处理中的第一个语句是调用存储过程时,你并不需要使用EXECUTE语句。你可以简单地提供存储过程的名称来执行存储过程。比如在ISQL/W中,可以象下面所示来执行存储过程: pro_book 这起同样的作用。存储过程会被执行,并会返回结果。然而如果在该存储过程之前还有其他的任何语句,你就会收到错误信息(一般地,语法错误)。 当你创建和执行一个存储过程时,这仅仅是在某一个数据库的范围内完成。假设你在数据库NetBBS内创建了存储过程pro_book。如果没有指明过程调用,你就不能在另一个数据库比如NetBBS2中调用存储过程pro_book。假如你需要在NetBBS2中执行存储过程pro_book,你必须使用如下的语句(注意下面的两个点号): EXECUTE NetBBS.. pro_book
ASP.NET完全入门(9)Public Class MyAccount:Inherits Control:Implements INamingContainer '从Control类继承,并且有自己的命名空间 Private _AcctNo As String Private _IdNo As String Private _Balance As Decimal Private _Stat As Status Public Event Click(Sender as Object,E as EventArgs) '定义控件自身的Click事件 '对属性存取的定义 Public Property AcctNo As String Get Return _AcctNo End Get Set _AcctNo = value End Set End Property Public Property IdNo As String Get Return _IdNo End Get Set _IdNo = value End Set End Property Public Property Balance As Decimal Get Return _Balance End Get Set _Balance = value End Set End Property Public Property Stat As Status Get Return _Stat End Get Set _Stat = value End Set End Property Public Sub New() MyBase.New Me.AcctNo = "" Me.IdNo = "" Me.Balance = "0.0" Me.Stat = "0" End Sub Protected Sub onClick(E as EventArgs) RaiseEvent Click(Me,E) End Sub '界面定义为4个属性文本输入框,加一个确定和取消键 Protected Overrides Sub CreateChildControls() Me.Controls.Add(New LiteralControl("<h3>客户帐号:")) dim txtAcctNo as New TextBox txtAcctNo.text=_AcctNo Me.Controls.Add(txtAcctNo) Me.Controls.Add(New LiteralControl("<br>身份证号:")) dim txtIdNo as New TextBox txtIdNo.text=_IdNo Me.Controls.Add(txtIdNo) Me.Controls.Add(New LiteralControl("<br>帐户余额:")) dim txtBalance as New TextBox txtBalance.text=_Balance Me.Controls.Add(txtBalance) Me.Controls.Add(New LiteralControl("<br>帐户状态:")) dim txtStat as New TextBox txtStat.text=_Stat Me.Controls.Add(txtStat) Me.Controls.Add(New LiteralControl("<br><br><br>")) dim Btn1 as New Button Btn1.text="确 认" AddHandler Btn1.Click,AddressOf Btn1_Click Me.Controls.Add(Btn1) dim Btn2 as New Button Btn2.text="取 消" Me.Controls.Add(Btn2) Me.Controls.Add(New LiteralControl("</h3>")) End Sub Private Sub Btn1_Click(Sender as Object,E as EventArgs) dim ctrl1 as TextBox=controls(1) Me.AcctNo=ctrl1.text dim ctrl2 as TextBox=controls(3) Me.IdNo=ctrl2.text dim ctrl3 as TextBox=controls(5) Me.Balance=CDbl(ctrl3.text) dim ctrl4 as TextBox=controls(7) Me.Stat=Cint(ctrl4.text) onClick(E) End Sub End Class End Namespace 2.控件编译文件 rem inherit.vb 的编译文件 文件名:form\CustomControl\i.bat vbc /t:library /out:.\bin\MyNamespaceVB.dll /r:System.Web.dll inherit.vb 3. 页面使用文件 <!--源文件:form\CustomControl\formInherit.aspx--> <%@ Register TagPrefix="MyNamespace" Namespace="MyNamespace" %> <html> <script language="vb" runat=server> sub acct_click(s as object, e as eventargs) dim strTxt as string strTxt="<hr>AcctNo="& acct1.AcctNo & "<br>" strTxt=strTxt & "IdNo=" & acct1.IdNo & "<br>" strTxt=strTxt & "Balance=" & acct1.Balance & "<br>" strTxt=strTxt & "Stat=" & acct1.Stat response.write(strTxt) end sub </script> <head> <title> 继承控件实验 </title> </head> <body bgcolor=#ccccff> <center> <h2>继承控件MyAccount的使用</h2> <hr> <br> <form action="forminherit.aspx" method="post" runat=server> <MyNamespace:MyAccount id="acct1" AcctNo="1234" IdNo="5678" onClick="acct_click" runat=server /> </form> </center> </body> </html> 4.开始的输出画面: 5.修改后,按确认键后的效果: 2.3.6小结 本章在前一章学习了服务器端控件的基础上,探讨了如何在利用已有控件的基础上,开发具有自己特色的自定义控件。使用自定义控件的好处在于: 1.简化了自己程序开发的周期 2.有助于形成具有自己特色的风格 3.隔离了错误发生的根源,修改自己定义的控件时,不必考虑其他因素 第四章HTML控件 HTML控件在服务器端是可见的,所以我们可以根据它来按照我们的意愿来编写。HTML控件表现为一些可见的控件。 2.4.1 HtmlButton HtmlButton server control 就象HTML4.0中的<button>一样,但是这与<Input type=”button”>不一样的,我们看下面的例子button.aspx: 响应按钮事件: <script language="VB" runat="server"> Sub Button1_onClick(sender As Object, e As EventArgs) Span1.InnerHtml="你点击了Button1" End Sub Sub Button2_onClick(sender As Object, e As EventArgs) Span1.InnerHtml="你点击了Button2" End Sub </script> 对两个button的描述: button1: <button id="Button1" onServerClick="Button1_onClick" style="font: 8pt verdana;background-color:lightgreen;border-color:black;height=30;width:1 00" runat="server"> <img src="/quickstart/aspplus/images/right4.gif"> Click me! </button> button2,我们增加了鼠标事件: <button id=Button2 onServerClick="Button2_onClick" style="font: 8pt verdana;background-color:lightgreen;border-color:black;height=30;width:100" onmouseover="this.style.backgroundColor='yellow'" onmouseout="this.style.backgroundColor='lightgreen'" runat="server"> Click me too! </button> 点击button2,并把鼠标移到它的上面: 第二节 Htmlform 一个Htmlform Control必须要处理PostBack请求,一个Web form只有一个<form>标记。form.aspx中form的表示: <form id=Serverform runat=server> <button id=Button1 runat="server" onServerClick="Button1_onClick">Button1</button> <span id=Span1 runat=server /> <p> <button id=Button2 runat="server" onServerClick="Button2_onClick">Button2</button> <span id=Span2 runat=server /> </form> 响应鼠标按钮事件: Sub Button1_onClick(sender As Object, e As EventArgs) Span1.InnerHtml = "It is Button1" End Sub Sub Button2_onClick(sender As Object, e As EventArgs) Span2.InnerHtml = "It is Button2" End Sub 看如下结果: 点击两个按钮,同时显示信息: 2.4.2 HtmlImages 我们通过一个<img src=””>这个标记来显示图片: <img ID="Image1" src="images/4.gif" runat="server"/> 我们根据ID号为<img >提供图片来源: Sub SubmitBtn_Click(sender As Object, e As EventArgs) Image1.Src="images/" & Select1.value End Sub 建立一个选择控件来与用户的交互: 选择面部表情文件: <select id="Select1" runat="server"> <option value="4.gif">4</option> <option value="5.gif">5</option> <option value="6.gif">6</option> <option value="7.gif">7</option> <option value="8.gif">8</option> <option value="9.gif">9</option> </select> <input type="submit" runat="server" value="提交" OnServerClick="SubmitBtn_Click"> 我们运行如下: 选择相应的文件号,点击按钮,图片就显示出来。 2.4.3 TextArea 象在HTML中的一样,在asp.net中的TextArea也是一个多行输入框。TextArea的宽度由他的Cols属性决定,长度由Rows属性决定。 Textarea.aspx中定义输入: <textarea id="TextArea1" cols=40 rows=4 runat=server /> 我们用TextArea1.value取得输入的值。具体如下(textarea.aspx): <!--源文件:form\HtmlControl\textarea.aspx--> <html> <head> <script language="VB" runat="server"> Sub SubmitBtn_Click(sender As Object, e As EventArgs) Span1.InnerHtml = "下面是你所写的 : <br>" & TextArea1.value End Sub </script> </head> <body bgcolor="#ccccff"> <h3><font face="Verdana">.NET->HtmlTextArea</font></h3> <form runat=server> <font face="Verdana" size="-1"> 写吧: <br> <textarea id="TextArea1" cols=40 rows=4 runat=server /> <input type=submit value="Submit" OnServerClick="SubmitBtn_Click" runat=server> <p> <span id="Span1" runat="server" /> </font> </form> </body> </html> 2.4.4 InputHidden 我们可以用隐藏输入控件来处理一些我们要传送而又不想在页面上显示出来的信息,例如在电子商务网站中,我们向银行网关接口传送我们的订单信息,我们就可以用隐藏输入控件来处理。 我们下面的例子用不可见的值来取得输入值,再把不可见值显示出来。 Inputhidden.aspx隐藏输入控件: <input id="Hiddenvalue" type=hidden value="隐藏的字符" runat=server> 初始值为“隐藏的字符“,在我们第一次点击按钮时候显示出来,我们的方法: Sub SubmitBtn_Click(sender As Object, e As EventArgs) Hiddenvalue.value = StringContents.value End Sub 这个方法把输入值赋给不可见的控件。我们完整的代码如下(hidden.aspx): <!--源文件:form\HtmlControl\hidden.aspx--> <html> <head> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If IsPostBack Then Span1.InnerHtml="隐藏值: <b>" & Hiddenvalue.value & "</b>" End If End Sub Sub SubmitBtn_Click(sender As Object, e As EventArgs) Hiddenvalue.value = StringContents.value End Sub </script> </head> <body> <h3><font face="Verdana">.NET->HtmlInputHidden</font></h3> <form runat=server> <input id="Hiddenvalue" type=hidden value="隐藏的字符" runat=server> 请输入: <input id="StringContents" type=text size=40 runat=server> <p> <input type=submit value="确定" OnServerClick="SubmitBtn_Click" runat=server> <p> <span id=Span1 runat=server>显示隐藏的字符</span> </form> </body> </html> 我们输入InputHidden,便点击按钮,则显示出默认的隐藏值。 2.4.5 HtmlTable HtmlTable服务控件能让你轻松的创建你的表格的行和列,也可以按照程序的模式自动生成表格。 我们的例子展示了这个特性: <table id="Table1" CellPadding=4 CellSpacing=0 Border="1" runat="server" /> 这就是在asp.net中,表格的表示。做两个Select控件来让用户选择表格的属性: <p> 行: <select id="Select1" runat="server"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> </select> <br> 列: <select id="Select2" runat="server"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> </select> 在用户提交的时候,实际上我们示对页面进行了刷新,即在Page_Load方法里面处理,具体如下(htmltable.aspx): <!--源文件:form\HtmlControl\htmltable.aspx--> <html> <head> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) Dim numrows As Integer Dim numcells As Integer Dim i As Integer = 0 Dim j As Integer = 0 Dim Row As Integer = 0 Dim r As HtmlTableRow Dim c As HtmlTableCell ' 产生表格 numrows = CInt(Select1.value) numcells = CInt(Select2.value) For j = 0 To numrows-1 r = new HtmlTableRow() If (row Mod 2 <> 0) Then r.BgColor = "Gainsboro" End If row += 1 For i = 0 To numcells-1 c = new HtmlTableCell() c.Controls.Add(new LiteralControl("row " & j & ", cell " & i)) r.Cells.Add(c) Next i Table1.Rows.Add(r) Next j End Sub </script> </head> <body> <h3><font face="Verdana">.NET->HtmlTable</font></h3> <form runat=server> <font face="Verdana" size="-1"> <p> <table id="Table1" CellPadding=4 CellSpacing=0 Border="1" runat="server" /> <p> 行: <select id="Select1" runat="server"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> </select> <br> 列: <select id="Select2" runat="server"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> </select> <input type="submit" value="产生表格" runat="server"> </font> </form> </body> </html> 选择并提交,我们的表格就出来了: 2.4.6 HtmlGenericControl HtmlGenericControl提供一个服务器控件,用来执行那些不直接的表现出来的未知的Html Control 标识。 例子文件Gerecolor.aspx: <!--源文件:form\HtmlControl\Gerecolor.aspx--> <html> <head> <script language="VB" runat="server"> Sub SubmitBtn_Click(sender As Object, e As EventArgs) Body.Attributes("bgcolor") = ColorSelect.value End Sub </script> </head> <body id=Body runat=server> <h3><font face="Verdana">.NET->HtmlGenericControl</font></h3> <form runat=server> <p> Select a background color for the page: <p> <select id="ColorSelect" runat="server"> <option>White</option> <option>Wheat</option> <option>Gainsboro</option> <option>LemonChiffon</option> </select> <input type="submit" runat="server" value="Apply" OnServerClick="SubmitBtn_Click"> </form> </body> </html> 我们的运行结果如下: 选择你所要的颜色,则面背景颜色就会改变。 2.4.7 HtmlInputButton 其实我们在上面的应用的时候就大概的应用过这个控件的,现在我们专门来讲讲它。这个控件有几个功能,可以是普通的按钮来响应一般的事件;可以是Submit按钮;也可以是Reset按钮。 2.4.7.1一般性的按钮 这个控件不是响应表单中通常的Submit或者Reset事件的,而是响应我们为他定制的的事件(button.aspx)。 <!--源文件:form\HtmlControl\button.aspx--> <html> <head> <script language="VB" runat="server"> Sub Button1_Click(sender As Object, e As EventArgs) Span1.InnerHtml = "你点击了这个按钮!" End Sub </script> </head> <h3><font face="Verdana">.NET->HtmlInputButton->button</font></h3> <form runat=server> <p> <input type=button value="Button1" onServerClick="Button1_Click" runat="server"> <span id=Span1 runat=server /> </form> </body> </html> 点击按钮,如下: 2.4.7.2 Submit与Reset 对这两个属性大家肯定很熟悉的了,在这里我们简单的介绍一下。在asp.net中,对这两个按钮,我们也用到了<input type= 这个标示,只是我们在后面加上runat=”server“,表示我们这个按钮在asp.net的框架之内,我们必须写方法来响应这个事件。如果没有runat=”server“这个修饰,我们可以把这个控件当作普通的html按钮,不用写法响应事件,如: <input type=reset value="重写" > 这是一个标准的html表示,我们在asp.net中的表示: <input type=submit value="提交" OnServerClick="SubmitBtn_Click" runat=server> 我们在按钮按下时候响应事件SubmitBtn_Click,具体如下(button2.aspx): <!--源文件:form\HtmlControl\button2.aspx--> <html> <head> <script language="VB" runat="server"> Sub SubmitBtn_Click(sender As Object, e As EventArgs) If Password.value = "saidy2001" Then Span1.InnerHtml = "密码正确!" Else Span1.InnerHtml="密码错误!" End If End Sub ' Sub ResetBtn_Click(sender As Object, e As EventArgs) ' Name.value = "" ' Password.value = "" 'End Sub </script> </head> <BODY BGCOLOR="#CCCCFF"> <h3><font face="Verdana">.NET->Submit and Reset</font></h3> <form runat=server> 输入名字: <input id="Name" type=text size=40 runat=server> <p> 输入密码: <input id="Password" type=password size=40 runat=server> (密码是: saidy2001) <p> <input type=submit value="提交" OnServerClick="SubmitBtn_Click" runat=server> <input type=reset value="重写" OnServerClick="ResetBtn_Click" runat=server> <p> <span id="Span1" style="color:red" runat=server></span> </form> </body> </html> 看到如下的效果: 输入名字和提示的密码,如下: 2.4.8 小结 本章介绍了服务器端的html控件,虽然它们的功能都可以以简单的html语言来实现,但是在asp.net中依然提供了对它们的实现。以html语言书写和以服务器端控件的实现在思维方式上已经有了很大的不同,对于html语言而言,只是一种标识;而对服务器端html控件而言,却已演变成为一段程序,一个对象。两者的区别不仅仅是,一个后缀名为.html,另一个为.aspx。html文件依赖于服务器端对标识的解释执行,html控件却可以被编译执行,两者在效率上的差异不言而喻。 第三篇 数据库编程 第一章 基本概念 ASP.NET中的ADO.NET和ASP中的ADO相对应,它是ADO的改进版本。在ADO.NET中,通过Managed Provider所提供的应用程序编程接口(API),可以轻松地访问各种数据源的数据,包括OLEDB所支持的和ODBC支持的数据库。 下面介绍ADO.NET中最重要的两个概念:Managed Provider和DataSet。 3.1.1 Managed Provider 过去,通过ADO的数据存取采用了两层的基于连接的编程模型。随着多层应用的需求不但增加,程序员需要一个无连接的模型。ADO.NET就应运而生了。ADO.NET的Managed Provider就是一个多层结构的无连接的一致的编程模型。 Managed Provider提供了DataSet和数据中心(如MS SQL)之间的联系。Managed Provider包含了存取数据中心(数据库)的一系列接口。主要有三个部件: l 连接对象Connection、命令对象Command、参数对象Parameter提供了数据源和DataSet之间的接口。DataSetCommand接口定义了数据列和表映射,并最终取回一个DataSet。 l 数据流提供了高性能的、前向的数据存取机制。通过IdataReader,你可以轻松而高效地访问数据流。 l 更底层的对象允许你连接到数据库,然后执行数据库系统一级的特定命令。 过去,数据处理主要依赖于两层结构,并且是基于连接的。连接断开,数据就不能再存取。现在,数据处理被延伸到三层以上的结构,相应地,程序员需要切换到无连接的应用模型。这样,DataSetCommand就在ADO.NET中扮演了极其重要的角色。它可以取回一个DataSet,并维护一个数据源和DataSet之间的“桥”,以便于数据访问和修改、保存。DataSetCommand自动将数据的各种操作变换到数据源相关的合适的SQL语句。从图上可以看出,四个Command对象:SelectCommand、InsertCommand、UpdateCommand、DeleteCommand分别代替了数据库的查询、插入、更新、删除操作。 Managed Provider利用本地的OLEDB通过COM Interop来实现数据存取。OLEDB支持自动的和手动的事务处理。所以,Managed Provider也提供了事务处理的能力。 3.1.2 DataSet DataSet是ADO.NET的中心概念。你可以把DataSet想象成内存中的数据库。正是由于DataSet,才使得程序员在编程序时可以屏蔽数据库之间的差异,从而获得一致的编程模型: DataSet支持多表、表间关系、数据约束等等。这些和关系数据库的模型基本一致。 3.1.2.1 TablesCollection对象 DataSet里的表(Table)是用DataTable来表示的。DataSet可以包含许多DataTable,这些DataTable构成TablesCollection对象。 DataTable定义在System.Data中,它代表内存中的一张表(Table)。它包含一个称为ColumnsCollection的对象,代表数据表的各个列的定义。DataTable也包含一个RowsCollection对象,这个对象含有DataTable中的所有数据。 DataTable保存有数据的状态。通过存取DataTable的当前状态,你可以知道数据是否被更新或者删除。 3.1.2.2 RelationsCollection对象 各个DataTable之间的关系通过DataRelation来表达,这些DataRelation形成一个集合,称为RelationsCollection,它是DataSet的子对象。DataRelation表达了数据表之间的主键-外键关系,当两个有这种关系的表之中的某一个表的记录指针移动时,另一个表的记录指针也随之移动。同时,一个有外键的表的记录更新时,如果不满足主键-外键约束,更新就会失败。 通过建立各个DataTable之间的DataRelation,可以轻松实现在ASP中需要通过DataShaping才能实现的功能。 3.1.2.3 ExtendedProperties对象 在这个对象里可以定义特定的信息,比如密码、更新时间等。 3.1.2.4 小结 本章首先介绍在asp.net中数据库编程的两个基本概念Managed Provider和DataSet。在asp.net中,DataSet屏蔽了具体数据源和应用之间差异,使得应用摆脱了具体数据的束缚。在我们今后的数据库编程中,可以把DataSet视为远端数据库在内存中的镜像,把繁琐的数据库操作任务交给Managed Provider去做 第二章 通过ADO.NET访问数据库 3.2.1 ADO.NET访问数据库的步骤 不论从语法来看,还是从风格和设计目标来看,ADO.NET都和ADO有显著的不同。在ASP中通过ADO访问数据库,一般要通过以下四个步骤: 1、 创建一个到数据库的链路,即ADO.Connection; 2、 查询一个数据集合,即执行SQL,产生一个Recordset; 3、 对数据集合进行需要的操作; 4、 关闭数据链路。 在ADO.NET里,这些步骤有很大的变化。ADO.NET的最重要概念之一是DataSet。DataSet是不依赖于数据库的独立数据集合。所谓独立,就是:即使断开数据链路,或者关闭数据库,DataSet依然是可用的。如果你在ASP里面使用过非连接记录集合(Connectionless Recordset),那么DataSet就是这种技术的最彻底的替代品。 有了DataSet,那么,ADO.NET访问数据库的步骤就相应地改变了: l 创建一个数据库链路; l 请求一个记录集合; l 把记录集合暂存到DataSet; l 如果需要,返回第2步;(DataSet可以容纳多个数据集合) l 关闭数据库链路; l 在DataSet上作所需要的操作。 DataSet在内部是用XML来描述数据的。由于XML是一种平台无关、语言无关的数据描述语言,而且可以描述复杂数据关系的数据,比如父子关系的数据,所以DataSet实际上可以容纳具有复杂关系的数据,而且不再依赖于数据库链路。 3.2.2 ADO.NET对象模型概览 3.2.2.1 ADOConnection ADO.NET有许多对象,我们先看看最基本的也最常用的几个。首先看看ADOConnection。和ADO的ADODB.Connection对象相对应,ADOConnection维护一个到数据库的链路。为了使用ADO.NET对象,我们需要引入两个NameSpace:System.Data和System.Data.ADO,使用ASP.NET的Import指令就可以了: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> 和ADO的Connection对象类似,ADOConnection对象也有Open和Close两个方法。下面的这个例子展示了如何连接到本地的MS SQL Server上的Pubs数据库。 <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <% '设置连接串... Dim strConnString as String strConnString = "Provider=SQLOLEDB; Data Source=(local); " & _ "Initial Catalog=pubs; User ID=sa" '创建对象ADOConnection Dim objConn as ADOConnection objConn = New ADOConnection '设置ADOCOnnection对象的连接串 objConn.ConnectionString = strConnString objConn.Open() '打开数据链路 '数据库操作代码省略 objConn.Close() '关闭数据链路 objConn = Nothing '清除对象 %> 上面的代码和ADO没有什么太大的差别。应该提到的是,ADO.NET提供了两种数据库连接方式:ADO方式和SQL方式。这里我们是通过ADO方式连接到数据库。关于建立数据库连接的详细信息,我们在后面的篇幅中将会讲到。 3.2.2.2 ADODatasetCommand 另一个不得不提到的ADO.NET对象是ADODatasetCommand,这个对象专门负责创建我们前面提到的DataSet对象。另一个重要的ADO.NET对象是Dataview,它是DataSet的一个视图。还记得DataSet可以容纳各种各种关系的复杂数据吗?通过Dataview,我们可以把DataSet的数据限制到某个特定的范围。 下面的代码展示了如何利用ADODatasetCommand为DataSet填充数据: '创建SQL字符串 Dim strSQL as String = "SELECT * FROM authors" '创建对象ADODatasetCommand 和Dataset Dim objDSCommand as ADODatasetCommand Dim objDataset as Dataset = New Dataset objDSCommand = New ADODatasetCommand(strSQL, objConn) '填充数据到Dataset '并将数据集合命名为 "Author Information" objDSCommand.FillDataSet(objDataset, "Author Information") 3.2.3显示Dataset 前面我们已经把数据准备好。下面我们来看看如何显示Dataset中的数据。在ASP.NET中,显示DataSet的常用控件是DataGrid,它是ASP.NET中的一个HTML控件,可以很好地表现为一个表格,表格的外观可以任意控制,甚至可以分页显示。这里我们只需要简单地使用它: <asp:DataGrid id="DataGridName" runat="server"/> 剩下的任务就是把Dataset绑定到这个DataGrid,绑定是ASP.NET的重要概念,我们将另文讲解。一般来说,你需要把一个Dataview绑定到DataGrid,而不是直接绑定Dataset。好在Dataset有一个缺省的Dataview,下面我们就把它和DataGrid绑定: MyFirstDataGrid.DataSource = _ objDataset.Tables("Author Information").DefaultView MyFirstDataGrid.DataBind() 3.2.4完整的代码 (code\122301.aspx) <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <% '设置连接串... Dim strConnString as String strConnString = "Provider=SQLOLEDB; Data Source=(local); " & _ "Initial Catalog=pubs; User ID=sa" '创建对象ADOConnection Dim objConn as ADOConnection objConn = New ADOConnection '设置ADOCOnnection对象的连接串 objConn.ConnectionString = strConnString objConn.Open() '打开数据链路 '创建SQL字符串 Dim strSQL as String = "SELECT * FROM authors" '创建对象ADODatasetCommand 和Dataset Dim objDSCommand as ADODatasetCommand Dim objDataset as Dataset = New Dataset objDSCommand = New ADODatasetCommand(strSQL, objConn) '填充数据到Dataset '并将数据集合命名为 "Author Information" objDSCommand.FillDataSet(objDataset, "Author Information") objConn.Close() '关闭数据链路 objConn = Nothing '清除对象 Authors.DataSource = _ objDataset.Tables("Author Information").DefaultView Authors.DataBind() %> <HTML> <BODY> <asp:DataGrid id="Authors" runat="server"/> </BODY> </HTML> 第三章 ADO.NET数据连接方法 3.3.1数据库连接字符串 一个Web应用往往包括几十上百个ASPX文件。如果在每一个文件里都是直接构造这个数据库连接字符串,首先是觉得麻烦,其次,如果数据库发生了什么变化,比如密码变化,或者IP变化,难道你都要改动每一个ASPX文件? 在《轻松组建网上商店》第一版里,我们通过把数据库连接字符串封装到Application(“strConn”)变量里面,在global.asa中初始化这个Application变量,从而解决了这个难题。 另外的一个解决方法就是写一个DbOpen函数,放到独立的一个ASP文件里,然后在其他的文件里包含这个DbOpen函数所在的文件。 这些方法在ASP时代非常流行。在ASP.NET时代,这些方法大部分依然有效,但是这里介绍的方法,却是利用了ASP.NET的特性。我们如果学习ASP.NET,就一定要按照ASP.NET的风格来编写代码。这样会给你带来意想不到的性能提高。 和在ASP里面类似,ASP.NET也有一个Application一级的配置文件,叫做config.web。通过简单地配置config.web,就可以解决数据库连接字符串问题: (config.web) <configuration> <appsettings> <add key="strConn" value="server=localhost;uid=sa;pwd=;Database=pubs"/> </appsettings> </configuration> 在aspx页面里,我们可以这样获得数据库连接字符串: Dim MyConnection As SQLConnection Dim Config as HashTable ‘把config.web的appsettings全部读到临时对象中 Config = Context.GetConfig("appsettings") ‘Config临时对象实际上是一个集合。 MyConnection = New SQLConnection(Config("MyConn")) 关于config.web的详细介绍,请阅读后面的章节。 此处要说明的是,本书为了使各个例子相对独立,没有采用上面介绍的方法。 3.3.2两种数据库连接方式 ASP.NET不仅带来了ADO.NET,还带来了SQL Managed Provider。这样在ASP.NET里,我们就有了两种连接数据库的方式: 1、ADO.NET Managed Provider 2、SQL Managed Provider 其中,方式一可以连接到任何ODBC或者OLEDB数据中心,而方式二可以连接到MS SQL Server。仅仅就MS SQL Server来讲,使用方式二在性能上要优于方式一。 下面我们来看看数据库连接的各种情况。 3.3.2.1 ADO.NET Managed Provider和ODBC 我们要连接的数据库是MS SQL Server中的pubs数据库。首先我们创建一个DSN:控制面板>>管理工具>>数据源(ODBC)>>添加: 下面的代码就创建了一个到MS SQL Server中pubs数据库的连接: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <script language=”VB” RunAt=”Server”> … '创建对象ADOConnection Dim objConn as ADOConnection=New ADOConnection(“DSN=pubs”) objConn.Open() '打开数据链路 … </script> 注意开始的两个Import语句。这是ADO.NET对象所在的Namespace。 ADO.NET Managed Provider+ODBC可以连接到各种数据源,包括:MS SQL Server、Access、Excel、mySQL、Oracle,甚至格式化的文本文件等等。 3.3.2.1.1一个完整的例子 <%@ Page Language="vb" %> <%@ Import Namespace = "System.Data" %> <%@ Import Namespace = "System.Data.ADO" %> <html> <head> <script runat=server> Sub Page_Load(ByVal Sender As Object, ByVal e As EventArgs) On Error Resume Next Dim cn As ADOConnection cn = New ADOConnection("DSN=NWind") cn.Open() If cn.State = 1 Then lblReturnCode.Text = "The Connection State is: " & cn.State & " - Connection Succeeded" Else lblReturnCode.Text = "The Connection State is: " & cn.State & " - Connection Failed" End If End Sub </script> </head> <body> <asp:Label id="lblReturnCode" Runat=server /> </body> </html> 3.3.2.2 ADO.NET Managed Provider和OLEDB 建立一个到OLEDB数据中心的连接,就需要精心构造数据库连接字符串。下面的代码建立了一个到Access数据库的连接: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <script language=”VB” RunAt=”Server”> … Dim cn As ADOConnection cn = New ADOConnection("provider=Microsoft.Jet.OLEDB.4.0; " & _ "Data Source=C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb;") cn.Open() … </script> 下面的代码建立了到MS SQL Server数据库的连接: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <script language=”VB” RunAt=”Server”> … Dim cn As ADOConnection cn = New ADOConnection("Provider=SQLOLEDB.1;Data Source=(local);uid=sa;pwd=;Initial Catalog=pubs”) cn.Open() … </script> ADO.NET目前支持下面的几个OLEDB: OLEDB驱动程序 提供者 SQLOLEDB SQL OLE DB Provider MSDAORA Oracle OLE DB Provider JOLT Jet OLE DB Provider MSDASQL/SQLServer ODBC SQL Server ODBC Driver via OLE DB for ODBC Provider MSDASQL/Jet ODBC Jet ODBC Driver via OLE DB Provider for ODBC Provider (数据来源:http://msdn.microsoft.com/library/default.asp?URL=/library/dotnet/cpguide/cpconaccessingdatawithado.htm ) 3.3.2.2.1一个完整的例子 <%@ Page Language="vb" %> <%@ Import Namespace = "System.Data" %> <%@ Import Namespace = "System.Data.ADO" %> <html> <head> <script runat=server> Sub Page_Load(ByVal Sender As Object, ByVal e As EventArgs) On Error Resume Next Dim cn As ADOConnection cn = New ADOConnection("provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Program Files\Microsoft Office\Office\Samples\Northwind.mdb;") cn.Open() If cn.State = 1 Then lblReturnCode.Text = "The Connection State is: " & cn.State & " - Connection Succeeded" Else lblReturnCode.Text = "The Connection State is: " & cn.State & " - Connection Failed" End If End Sub </script> </head> <body> <asp:Label id="lblReturnCode" Runat=server /> </body> </html> 3.3.2.3 SQL Managed Provider和Microsoft SQL Server 通过SQL Managed Provider 建立到MS SQL Server的连接很简单: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <script language=”VB” RunAt=”Server”> … Dim objConn as SQLConnection = New ADOConnection("server=localhost;uid=sa;pwd=;database=pubs;") objConn.Open() '打开数据链路 … </script> 请注意几个地方: 1、 Import语句的不同。在ADO.NET Managed Provider里面,我们Import的是System.Data.ADO;而这里需要System.Data.SQL; 2、 连接对象也不同。在ADO.NET Managed Provider中,所有的对象以ADO打头;而这里需要以SQL打头。 下面的表格归纳了这些不同: ADO.NET Managed Provider ADO.NET SQL Managed Provider 需要引入的Namespace System.Data.ADO System.Data.SQL Connection对象 ADOConnection SQLConnection Command对象 ADODatasetCommand SQLDatasetCommand Dataset对象 Dataset Dataset DataReader ADODataReader SQLDataReader 连接数据库例子 String sConnectionString = "Provider= SQLOLEDB.1; Data Source=localhost; uid=sa; pwd=; Initial Catalog=pubs"; ADOConnection con = new ADOConnection(sConnectionString); con.Open(); String sConnectionString = "server=localhost;uid=sa;pwd=;database=pubs"; SQLConnection con = new SQLConnection(sConnectionString); con.Open(); 执行SQL语句例子 ADOCommand cmd = new ADOCommand("SELECT * FROM Authors", con); ADODataReader dr = new ADODataReader(); cmd.Execute(out dr); SQLCommand cmd = new SQLCommand(("SELECT * FROM Authors", con); SQLDataReader dr = new SQLDataReader(); cmd.Execute(out dr); 使用存储过程例子 ADOCommand cmd = new ADOCommand ("spGetAuthorByID", con); cmd.CommandType = CommandType.StoredProcedure; ADOParameter prmID = new ADOParameter("AuthID", ADODataType.VarChar, 11); prmID.value = "111-11-1111"; cmd.SelectCommand.Parameters.Add(prmID); ADODataReader dr; cmd.Execute (out dr); SQLCommand cmd = new SQLCommand("spGetAuthorByID", con); cmd.CommandType = CommandType.StoredProcedure; SQLParameter prmID = new SQLParameter("@AuthID", SQLDataType.VarChar,11); prmID.value = "111-11-1111" cmd.SelectCommand.Parameters.Add(prmID); SQLDataReader dr; cmd.Execute(out dr); 3.3.2.3.1一个完整的例子 <%@ Page Language="vb" %> <%@ Import Namespace = "System.Data" %> <%@ Import Namespace = "System.Data.SQL" %> <html> <head> <script runat=server> Sub Page_Load(ByVal Sender As Object, ByVal e As EventArgs) 'On Error Resume Next Dim cn As SQLConnection cn = New SQLConnection("server=localhost;uid=sa;pwd=;database=pubs;") cn.Open() If cn.State = 1 Then lblReturnCode.Text = "The Connection State is: " & cn.State & " - Connection Succeeded" Else lblReturnCode.Text = "The Connection State is: " & cn.State & " - Connection Failed" End If End Sub </script> </head> <body> <asp:Label id="lblReturnCode" Runat=server /> </body> </html> ASP.NET完全入门(8)请看程序的运行效果:
第一步: 第二步: 第三步: 大家可以留意浏览器的地址栏,我们注意到地址都是相同的。我就是我们使用pann控件所得到的效果。 2.2.10 选择控件 选择的方式有两种:单选、多选。我们下面用具体的例子来说明这两种选择控件在asp.net 上的实现。 对单选控件,asp.net里面有一个专用的表示:RadioButtonList,我们看下面的代码: <!--列出选择内容--> <ASP:RadioButtonList id=ccType Font-Name="Arial" RepeatLayout="Flow" runat=server> <asp:ListItem>招行一卡通</asp:ListItem> <asp:ListItem>牡丹卡</asp:ListItem> </ASP:RadioButtonList> 我们在取值的时候,就可以用一个语句: Request.QueryString(“ccType”) 来取得这个值。下面是我们这个说明的完整代码(RadioButtonList.aspx): <!--源文件:form\ServerControl\RadioButtonList.aspx--> <html> <body > <center> <br><br> <h3><font face="Verdana">.NET->选择控件!</font></h3> <br><br><br> </center> <form method=post runat=server> <hr width=600 size=1 noshade> <center> <asp:ValidationSummary ID="valSum" runat="server" HeaderText="你必须填写下面的内容:" DisplayMode="SingleParagraph" Font-Name="verdana" Font-Size="12" /> <p> <!-- 信用卡信息 --> <table border=0 width=600> <tr> <td colspan=3> <center> <font face=Arial size=2><b>信用卡信息</b></font> </center> </td> </tr> <tr> <td align=right> <font face=Arial size=2>信用卡类型:</font> </td> <td> <!--列出选择内容--> <ASP:RadioButtonList id=ccType Font-Name="Arial" RepeatLayout="Flow" runat=server> <asp:ListItem>招行一卡通</asp:ListItem> <asp:ListItem>牡丹卡</asp:ListItem> </ASP:RadioButtonList> </td> <td> <asp:RequiredFieldValidator id="ccTypeReqVal" ControlToValidate="ccType" ErrorMessage="信用卡类型. " Display="Static" Initialvalue="" Font-Name="Verdana" Font-Size="12" runat=server> * </asp:RequiredFieldValidator> </td> </tr> </table> <p> <input runat="server" type=submit value="提交"> <p> <hr width=600 size=1 noshade> </form> </center> </body> </html> 我们的运行效果如下: 我们选择一个并提交,则会提交成功;反之,如果我们没有选择就提交,会出现如下的信息: 我们再来看看多选的情况: '选择项列表 <asp:CheckBoxList id=Check1 runat="server"> <asp:ListItem>北京</asp:ListItem> <asp:ListItem>深圳</asp:ListItem> <asp:ListItem>上海</asp:ListItem> <asp:ListItem>广州</asp:ListItem> <asp:ListItem>南宁</asp:ListItem> <asp:ListItem>重庆</asp:ListItem> </asp:CheckBoxList> 跟我们上面的单选控件就相差在定义上,我们用CheckBoxList来描述我们的选择框,我们写一个方法来响应我们的“提交“事件: '响应按钮事件 Sub Button1_Click(sender As Object, e As EventArgs) Dim s As String = "被选择的选项是:<br>" Dim i As Int32 For i = 0 to Check1.Items.Count-1 If Check1.Items(i).Selected Then '列出选择项 s = s & Check1.Items(i).Text s = s & "<br>" End If Next '打印出选择项 Label1.Text = s End Sub 这个方法为定义打印被选择的选项。具体的内容如下(list.aspx): <!--源文件:form\ServerControl\list.aspx--> <html> <head> <script language="VB" runat="server"> '响应按钮事件 Sub Button1_Click(sender As Object, e As EventArgs) Dim s As String = "被选择的选项是:<br>" Dim i As Int32 For i = 0 to Check1.Items.Count-1 If Check1.Items(i).Selected Then '列出选择项 s = s & Check1.Items(i).Text s = s & "<br>" End If Next '打印出选择项 Label1.Text = s End Sub </script> </head> <body bgcolor="#ccccff"> <br><br><br> <center> <h3><font face="Verdana">.NET->CheckBoxList</font></h3> </center> <br><br> <center> <form runat=server> '选择象列表 <asp:CheckBoxList id=Check1 runat="server"> <asp:ListItem>北京</asp:ListItem> <asp:ListItem>深圳</asp:ListItem> <asp:ListItem>上海</asp:ListItem> <asp:ListItem>广州</asp:ListItem> <asp:ListItem>南宁</asp:ListItem> <asp:ListItem>重庆</asp:ListItem> </asp:CheckBoxList> <p> <asp:Button id=Button1 Text="提交" onclick="Button1_Click" runat="server"/> <p> <asp:Label id=Label1 font-name="Verdana" font-size="8pt" runat="server"/> </form> </center> </body> </html> 我们看到显示如下: 选择几个选项,并点击“提交“按钮“,看到如下的情况: 2.2.11 ImageButton 控件 ImageButton 控件 当我们在浏览网页的时候,可能会发现这样一种情况:当鼠标移到图象按钮上和当鼠标移走的时候,将会发现同一按钮上将会显示不同的两个图片。我们可以用Image Button控件的 onmouseout 和 onmouseover 事件来实现。 请看Image.aspx中的代码: <!--源文件:form\ServerControl\image.aspx--> <html> <Body BgColor="White"> <center><H3>ImageButton 控件演示</H3></center> <title>ImageButton 控件演示</title> <script Language="VB" runat="server"> Sub Button1_Click(sender As Object, e As ImageClickEventArgs) ’定义当我们点击按钮的时候,将访问的网页 Page.Navigate( "http://www.yesky.com" ) End Sub </script> <form runat="server"> <center> <asp:ImageButton onClick="Button1_Click" ImageUrl="18.gif" id="Button1" runat="server" onMouseOut="this.src=ཎ.gif'" onMouseOver="this.src=ཏ.gif'" /> </center> </form> <asp:Label id="Label1" runat="server"/> </Body> </Html> 在这段程序中,我们使用了onmouseout和onmouseover事件。 请看程序的演示效果: 当鼠标移动到按钮上的时候,将显示: 2.2.12 列表控件 在asp.net中,有几种方法可以应用于列表控件。我们可以在aspx代码中直接嵌入相关 的代码,也可以在页面装入的时候加载这些列表信息。 下面是具体的应用,我们先看看在aspx中的列表方法: <!--列表->列出内容--> <asp:DropDownList id=DropDown1 runat="server"> <asp:ListItem>北京</asp:ListItem> <asp:ListItem>深圳</asp:ListItem> <asp:ListItem>上海</asp:ListItem> <asp:ListItem>广州</asp:ListItem> <asp:ListItem>南宁</asp:ListItem> <asp:ListItem>重庆</asp:ListItem> </asp:DropDownList> 我们在需要取出所选的数据时,直接去取id值,即DropDown1;我们再定一一个方法,响应“提交“按钮的事件,就可以了。下面是完整的代码(DropDown.aspx): <!--源文件:form\ServerControl\dropdown.aspx--> <html> <head> <script language="VB" runat="server"> '在点击按钮时候响应 Sub list_Click(sender As Object, e As EventArgs) Label1.Text="你的选择是: " + DropDown1.SelectedItem.Text End Sub </script> </head> <body bgcolor="#ccccff"> <br><br><br> <center> <h3><font face="Verdana">.NET->列表控件</font></h3> </center> <br><br> <center> <form runat=server> <!--列表->列出内容--> <asp:DropDownList id=DropDown1 runat="server"> <asp:ListItem>北京</asp:ListItem> <asp:ListItem>深圳</asp:ListItem> <asp:ListItem>上海</asp:ListItem> <asp:ListItem>广州</asp:ListItem> <asp:ListItem>南宁</asp:ListItem> <asp:ListItem>重庆</asp:ListItem> </asp:DropDownList> <asp:button text="提交" onClick="list_Click" runat=server/> <p> <asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server"> </asp:Label> </form> </center> </body> </html> 我们看看运行效果: 点击提交按钮时候看到下面的效果: 下面我们再来看看另外一个列表控件的使用,我们定义一个在页面装载的时候调用的方法: '再页面装载的时候调用的方法: Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim values as ArrayList= new ArrayList() values.Add ("北京") values.Add ("深圳") values.Add ("上海") values.Add ("广州") values.Add ("南宁") values.Add ("重庆") '设定DropDown1的数据源为values,即上面定义的信息 DropDown1.DataSource = values '数据的绑定 DropDown1.DataBind End If End Sub 我们在aspx代码中调用它: <!--列出列表信息--> <asp:DropDownList id="DropDown1" runat="server" /> 就这样的一个简单的语句就可以了,下面是这个文件的完整的代码: <html> <head> <script language="VB" runat="server"> '再页面装载的时候调用的方法: Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim values as ArrayList= new ArrayList() values.Add ("北京") values.Add ("深圳") values.Add ("上海") values.Add ("广州") values.Add ("南宁") values.Add ("重庆") '设定DropDown1的数据源为values,即上面定义的信息 DropDown1.DataSource = values '数据的绑定 DropDown1.DataBind End If End Sub '提交按钮响应的方法 Sub select02_Click(sender As Object, e As EventArgs) Label1.Text = "你的选择是: " + DropDown1.SelectedItem.Text End Sub </script> </head> <body BGCOLOR="#CCCCFF"> <br><br><br> <center> <h3><font face="Verdana">.NET->列表控件</font></h3> </center> <br><br> <center> <form runat=server> <!--列出列表信息--> <asp:DropDownList id="DropDown1" runat="server" /> <asp:button Text="提交" onClick="select02_Click" runat=server/> <p> <asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server" /> </form> </center> </body> </html> 运行的结果跟上面的一样。 2.2.13 重复列表Repeator
这种服务器控件会以给定的形式重复显示数据项目,故称之为重复列表。使用重复列表有两个要素,即数据的来源和数据的表现形式。数据来源的指定由控件的DataSource属性决定,并调用方法DataBind绑定到控件上。这里需要说明的是数据取出以后如何表现的问题,即如何布局。重复列表的数据布局是由给定的模板来决定的,由于重复列表没有缺省的模板,所以使用重复列表时至少要定义一个最基本的模板“ItemTemplate”。 重复列表支持以下模板标识,所谓模板就是预先定义的一种表现形式,以后我们还会就这个问题专门讨论,这里就不在多说。 1)ItemTemplate模板,数据项模板,必需的,它定义了数据项极其表现形式。 2)AlternatingItemTemplate模板,数据项交替模板,为了使相邻的数据项能够有所区别,可以定义交替模板,它使得相邻的数据项看起来明显不同,缺省情况下,它和ItemTemplate模板定义一致,即缺省下相邻数据项无表示区分。 3)SeparatorTemplate模板,分割符模板,定义数据项之间的分割符。 4)HeaderTemplate模板,报头定义模板,定义重复列表的表头表现形式。 5)FooterTemplate模板,表尾定义模板,定义重复列表的列表尾部的表现形式。 切记,由于缺乏内置的预定义模板和风格,在使用重复列表时,请一定记住要使用HTML格式定义自己的模板。 下面给出一个例子,看它是如何使用重复列表控件的。下面的例子首先在页面加载过程时把数据装载,并绑定到两个重复列表上;然后以一个2列的表格显示;最后把所有数据显示到一行上面,并且国家和领导人之间以3个中横线分隔,每一国家之间以竖划线分隔。 1.源代码(formRepeater.aspx) <!--源文件:form\ServerControl\formRepeater.aspx--> <html> <head> <script language="vb" runat=server> Class Leader '定义一个类Leader dim strCountry as String dim strName as String Public Sub New(country As String, name As String) MyBase.New strName = name strCountry= country End Sub ReadOnly Property Name As String Get Return strName End Get End Property ReadOnly Property Country As String Get Return strCountry End Get End Property End Class sub Page_Load(s as object,e as eventargs) dim leaders as ArrayList = New ArrayList() if Not Page.IsPostBack '加载数据 leaders.add(new leader("美利坚","布 什")) leaders.add(new leader("俄罗斯","普 京")) leaders.add(new leader("中 国","天涯风云")) Repeater1.DataSource=leaders Repeater2.DataSource=leaders Repeater1.DataBind Repeater2.DataBind end if end sub </script> <title> 重复列表使用例子 </title> </head> <center> <h2>重复列表的使用</h2> <hr> <br> '以表格形式显示国家,领导人信息 <asp:Repeater id="Repeater1" runat=server> '定义表头 <template name=HeaderTemplate> <table border=2> <tr> <th> 国家名 </th> <th> 领导人 </th> </tr> </template> '定义数据显示格式 <template name=ItemTemplate> <tr> <td> <%# DataBinder.Eval(Container.DataItem,"Country") %> </td> <td> <%# DataBinder.Eval(Container.DataItem,"Name") %> </td> </tr> </template> '定义表尾 <template name=FooterTemplate> <tr> <td>日期</td> <td>2001年</td> </tr> </table> </template> </asp:Repeater> <br> <asp:Repeater id=Repeater2 runat=server> '国家和领导人以│分割显示 <template name=ItemTemplate> <%# DataBinder.Eval(Container.DataItem,"Country") %> --- <%# DataBinder.Eval(Container.DataItem,"Name") %> </template> <template name=SeparatorTemplate> │ </template> </asp:Repeater> </center> </body> <html> 2.输出结果 2.2.14 数据列表 DataList 数据列表显示跟重复列表(Repeator)比较类似,但是它可以选择和修改数据项的内容。数据列表的数据显示和布局也如同重复列表都是通过“模板”来控制的。同样的,模板至少要定义一个“数据项模板”(ItemTemplate)来指定显示布局。数据列表支持的模板类型更多,它们如下: 1)ItemTemplate模板,数据项模板,必需的,它定义了数据项极其表现形式。 2)AlternatingItemTemplate模板,,数据项交替模板,为了使相邻的数据项能够有所区别,可以定义交替模板,它使得相邻的数据项看起来明显不同,缺省情况下,它和ItemTemplate模板定义一致,即缺省下相邻数据项无表示区分。 3)SeparatorTemplate模板,分割符模板,定义数据项之间的分割符。 4)SelectedItemTemplate模板,选中项模板,定义被选择的数据项的表现内容与布局形式,当未定义”SelectedItemTemplate”模板时,选中项的表现内容与形式无特殊化,由ItemTemplate模板定义所决定。 5)EditItemTemplate模板,修改选项模板,定义即将被修改的数据项的显示内容与布局形式,缺省情况下,修改选项模板就是数据项模板(ItemTemplate)的定义。 6)HeaderTemplate模板,报头定义模板,定义重复列表的表头表现形式。 7)FooterTemplate模板,表尾定义模板,定义重复列表的列表尾部的表现形式。 数据列表还可以通过风格形式来定义模板的字体、颜色、边框。每一种模板都有它自己的风格属性。例如,可以通过设置修改选项模板的风格属性来指定它的风格。 此外,还有一些其他属性可以导致数据列表的显示有较大的改变,下面择重说明。 RepeatLayout:显示布局格式,指定是否以表格形式显示内容。 RepeatLayout.Table指定布局以表格形式显示。 RepeatLayout.Flow指定布局以流格式显示,即不加边框。 RepeatDirection:显示方向,指定显示是横向显示还是纵向显示 RepeatDirection.Horizontal指定是横向显示 RepeatDirection.Vertical指定是纵向显示 RepeatColumns:一行显示列数,指定一行可以显示的列数,缺省情况下,系统设置为一行显示一列。这里需要注意的是,当显示方向不同时,虽然一行显示的列数不变,但显示的布局和显示内容的排列次序却有可能大不相同。 例如:有10个数据需要显示,RepeatColumns设定为4,即一行显示4列时 当RepeatDirection=RepeatDirection.Horizontal横向显示时,显示布局如下: Item1Item2Item3Item4 Item5Item6Item7Item8 Item9Item10 当RepeatDirection=RepeatDirection.Vertical纵向显示时,显示布局如下: Item1Item4Item7Item10 Item2Item5Item8 Item3Item6Item9 BorderWidth:当RepeatLayout=RepeatLayout.Table即以表格形式显示时,边框的线宽度 Unit.Pixel(x) x>=0,当x为0时无边框 GridLines: 当RepeatLayout=RepeatLayout.Table以表格形式显示时,在表格当中是否有网隔线分离表格各单元。 GridLines=GridLines.Both,有横向和纵向两个方向的分割线。 GirdLines=GridLines.None,无论横向还是纵向均无分割线。 例子:演示以上介绍的各属性的设置对数据列表输出的影响,并且当数据项被选中时,数据项以粉红色来反显。 1.源程序(DataList.aspx) <!--源文件:form\ServerControl\dataList.aspx--> <%@ Import Namespace="System.Data" %> <html> <script language="VB" runat="server"> '创建初始化表和载入实验数据 Function LoadData() As ICollection Dim dt As DataTable Dim dr As DataRow Dim i As Integer '创建数据表 dt = New DataTable '建立数据项结构 dt.Columns.Add(New DataColumn("Content", GetType(String))) '载入10个实验数据 For i = 1 To 10 dr = dt.NewRow() dr(0) = "Info " & i.ToString() dt.Rows.Add(dr) Next '为数据表建立一个数据视图,并将其返回 LoadData = New DataView(dt) End Function Sub Page_Load(s As Object, e As EventArgs) If Not IsPostBack Then DataList1.DataSource = LoadData() DataList1.DataBind End If End Sub Sub DataList1_ItemCommand(s As Object, e As DataListCommandEventArgs) Dim cmd As String = e.CommandSource.CommandName If cmd = "select" Then DataList1.SelectedIndex = e.Item.ItemIndex End If DataList1.DataSource = LoadData() DataList1.DataBind End Sub '当刷新按钮按下后,对数据列表属性重新设置 Sub RefreshBtn_Click(s As Object, e As EventArgs) If lstDirection.SelectedIndex = 0 DataList1.RepeatDirection = RepeatDirection.Horizontal Else DataList1.RepeatDirection = RepeatDirection.Vertical End If If lstLayout.SelectedIndex = 0 DataList1.RepeatLayout = RepeatLayout.Table Else DataList1.RepeatLayout = RepeatLayout.Flow End If If chkBorder.Checked And DataList1.RepeatLayout = RepeatLayout.Table Then DataList1.BorderWidth = Unit.Pixel(1) Else DataList1.BorderWidth = Unit.Pixel(0) End If If chkGridLines.Checked And DataList1.RepeatLayout = RepeatLayout.Table then DataList1.GridLines = GridLines.Both Else DataList1.GridLines = GridLines.None End If DataList1.RepeatColumns=lstColsPerLine.SelectedIndex + 1 End Sub </script> <head> <title> 数据列表实验 </title> </head> <body> <center> <h2> 数据列表属性方法实验 </h2> <form runat=server> <font face="Verdana" size="-1"> <asp:DataList id="DataList1" runat="server" BorderColor="black" CellPadding="3" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#aaaadd" AlternatingItemstyle-BackColor="#ccccff" SelectedItemstyle-BackColor="#ffccff" OnItemCommand="DataList1_ItemCommand" > <template name="HeaderTemplate"> <h><center>内容</center></h> </template> <template name="ItemTemplate"> <asp:LinkButton id="DetailBtn" runat="server" Text="详细" CommandName="select" /> <%# DataBinder.Eval(Container.DataItem, "Content") %> </template> <template name="SelectedItemTemplate"> <%# DataBinder.Eval(Container.DataItem, "Content") %>已经被选中 </template> </asp:DataList> <p> <hr> 显示方向: <asp:DropDownList id=lstDirection runat="server"> <asp:ListItem>横向</asp:ListItem> <asp:ListItem>纵向</asp:ListItem> </asp:DropDownList> 布局类型: <asp:DropDownList id=lstLayout runat="server"> <asp:ListItem>表方式</asp:ListItem> <asp:ListItem>流方式</asp:ListItem> </asp:DropDownList> 一行列数: <asp:DropDownList id=lstColsPerLine runat="server"> <asp:ListItem>1列</asp:ListItem> <asp:ListItem>2列</asp:ListItem> <asp:ListItem>3列</asp:ListItem> <asp:ListItem>4列</asp:ListItem> <asp:ListItem>5列</asp:ListItem> </asp:DropDownList> 边框显示: <asp:CheckBox id=chkBorder runat="server" /> 网格显示: <asp:CheckBox id=chkGridLines runat="server" /> <p> <asp:Button id=RefreshBtn Text="刷新界面" onClick="RefreshBtn_Click" runat="server"/> </font> </form> </center> </body> </html> 2.开始时的界面显示如下,(方向为横向,表方式,一行一列,无边框及网格) 3.当选择显示方向为横向,表方式,一行含5列,显示边框和网格时,界面显示如下: 4.选择纵向显示,表方式,一行含5列,无边框,无网格时,界面显示如下: 5.当在步骤4的基础上选择了第5项数据项时,界面显示如下: 接下来,我们讨论一下一种比较有实际意义的应用,即对选中数据项的修改的实现。 首先是对模板EditItemTemplate的定义,通常做法是排列可以进行修改的内容,然后定义一个修改确认键和一个修改取消键。 然后应定义数据列表支持的三种消息处理函数即OnEditCommand、OnUpdateCommand、OnCancelCommand(编辑事件处理、修改事件处理、撤消修改事件处理) 编辑事件处理:通常设置数据列表的EditItemIndex属性为选中的数据项索引,然后重载数据列表。 Protected Sub DataList_EditCommand(Source As Object, e As DataListCommandEventArgs) DataList1.EditItemIndex = CType(e.Item.ItemIndex, Integer) ‘重新加载并绑定数据 BindList() End Sub 取消修改事件处理:通常设置数据列表的EditItemIndex为-1,表示没有数据项需要修改,然后重载数据列表 Protected Sub DataList_CancelCommand(Source As Object, e As DataListCommandEventArgs) DataList1.EditItemIndex = -1 BindList() End Sub 修改事件处理:通常先修改数据源的数据,然后设置数据列表的EditItemIndex为-1,最后重载数据列表。 Sub DataList_UpdateCommand(Source As Object, e As DataListCommandEventArgs) ‘修改数据源数据,应根据具体情况而变 ModifySource() DataList.EditItemIndex=-1 BindList End Sub 例子:显示一个关于书籍修改的实例。一条书籍记录包含序号、书名、价格信息。初始化数据时,我们设置序号为1-6,书名为“书名”+序号,价格为1.11*序号。 1.源程序(formDataList01.aspx) <<!--源文件:form\ServerControl\formDataList01.aspx--> <%@ Import Namespace="System.Data" %> <html> <script language="VB" runat="server"> dim Book As DataTable dim BookView As DataView '设置数据源,并绑定 Sub BindList() DataList1.DataSource= BookView DataList1.DataBind End Sub Sub Page_Load(s As Object, e As EventArgs) Dim dr As DataRow '如果没有连接变量session_book,定义数据表Book,并载入实验数据 if session("session_Book") = Nothing then Book = New DataTable() Book.Columns.Add(new DataColumn("num", GetType(string))) Book.Columns.Add(new DataColumn("name", GetType(String))) Book.Columns.Add(new DataColumn("price", GetType(String))) session("session_Book") = Book '载入部分测试数据 For i = 1 To 6 dr = Book.NewRow() dr(0)=i.ToString dr(1) = "书名 " & i.ToString dr(2) = ( 1.11* i).ToString Book.Rows.Add(dr) Next '有session_book变量,直接引用 Else Book = session("session_Book") end if '产生数据视图,并按num字段排序 BookView = New DataView(Book) BookView.Sort="num" '初次需绑定数据源 if Not IsPostBack then BindList End If End Sub '编辑处理函数 Sub DataList_EditCommand(sender As Object, e As DataListCommandEventArgs) DataList1.EditItemIndex = e.Item.ItemIndex BindList End Sub '取消处理函数 Sub DataList_CancelCommand(sender As Object, e As DataListCommandEventArgs) DataList1.EditItemIndex = -1 BindList End Sub '更新处理函数 Sub DataList_UpdateCommand(sender As Object, e As DataListCommandEventArgs) Dim lbl1 As Label = e.Item.FindControl("lblNum") Dim txt2 As TextBox = e.Item.FindControl("txtBook") Dim txt3 As TextBox = e.Item.FindControl("txtPrice") dim strNum as String dim strBook as String dim strPrice as String strNum=lbl1.text strBook=txt2.text strPrice=txt3.text '用先删除再插入的方式,实现数据的更新操作 BookView.RowFilter = "num='" & strNum & "'" If BookView.Count > 0 Then BookView.Delete(0) End If BookView.RowFilter = "" dim dr as DataRow=Book.NewRow() dr(0) = strNum dr(1) = strBook dr(2) = strPrice Book.Rows.Add(dr) DataList1.EditItemIndex = -1 BindList End Sub </script> <head> <title> 数据列表修改实验 </title> </head> <body> <center> <h2>数据列表修改实验</h2> <hr> <p></p> <form runat=server> <font face="Verdana" size="-1"> <!--编辑时显示绿色,并定义编辑、修改、取消时的处理函数--> <asp:DataList id="DataList1" runat="server" BorderColor="black" BorderWidth="1" GridLines="Both" CellPadding="3" CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Width="150px" Headerstyle-BackColor="#aaaadd" AlternatingItemstyle-BackColor="Gainsboro" EditItemstyle-BackColor="green" OnEditCommand="DataList_EditCommand" OnUpdateCommand="DataList_UpdateCommand" OnCancelCommand="DataList_CancelCommand" > <template name="HeaderTemplate"> <center><h>书籍序号</h></center> </template> <template name="ItemTemplate"> <asp:LinkButton id="button1" runat="server" Text="详细" CommandName="edit" /> <%# Container.DataItem("name") %> </template> <template name="EditItemTemplate"> 书籍: 序号 <asp:Label id="lblNum" runat="server" Text='<%# Container.DataItem("num") %>' /><br> 书名: <asp:TextBox id="txtBook" runat="server" Text='<%# Container.DataItem("name") %>' /><br> 价格: <asp:TextBox id="txtPrice" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "price") %>' /> <br> <center> <asp:Button id="button2" runat="server" Text="修 改" CommandName="update" /> <asp:Button id="button3" runat="server" Text="撤 消" CommandName="cancel" /> </center> </template> </asp:DataList> </font> </form> </center> </body> </html> 2.准备对第2项进行修改,此时的画面如下: 3.把序号为2的书籍的价格改为9.99以后,重新进入其编辑状态后,它的输出画面如下: sgtkdxyyh 2.2.15 数据表格DataGrid 数据表格服务器端控件以表格形式显示数据内容,同时还支持数据项的选择、排序、分页和修改。缺省情况下,数据表格为数据源中每一个域绑定一个列,并且根据数据源中每一个域中数据的出现次序把数据填入数据表格中的每一个列中。数据源的域名将成为数据表格的列名,数据源的域值以文本标识形式填入数据表格中。 通过直接操作表格的Columns集合,可以控制数据表格各个列的次序、表现方式以及显示内容。缺省的列为Bound型列,它以文本标识的形式显示数据内容。此外,还有许多类型的列类型可供用户选择。 列类型的定义有两种方式:显视的用户定义列类型和自动产生的列类型(AutoGenerateColumns)。当两种列类型定义方式一起使用时,先用用户定义列类型产生列的类型定义,接着剩下的再使用自动列定义规则产生出其他的列类型定义。请注意自动定义产生的列定义不会加入Columns集合。 列类型介绍: 1)bound column ,列可以进行排序和填入内容。这是大多数列缺省用法。 两个重要的属性为:HeaderText指定列的表头显示 DataField指定对应数据源的域 2)hyperlink column,列内容以hyperlink控件方式表现出来。它主要用于从数据表格的一个数据项跳转到另外的一个页面,做出更详尽的解释或显示。 重要的属性有: HeaderText指定列表头的显示 DataNavigateUrlField指定对应数据源的域作为跳转时的参数 DataNavigateUrlformatString指定跳转时的url格式 DataTextField指定数据源的域作为显示列内容来源 3)button column,把一行数据的用户处理交给数据表格所定义的事件处理函数。通常用于对某一行数据进行某种操作,例如,加入一行或者是删去一行数据等等。 重要的属性有: HeaderText指定列表头的显示 Text指定按钮上显示的文字 CommandName指定产生的激活命令名 4)Template column,列内容以自定义控件组成的模板方式显示出来。通常用作用户需要自定义显示格式的时候。 5)Edit Command column,当数据表格的数据项发生编辑、修改、取消修改时,相应处理函数的入口显示。它通常结合数据表格的EditItemIndex属性来使用,当某行数据需要编辑、修改、取消操作时,通过它进入相应的处理函数。例如,当需要对某行数据进行修改(update)时,通过它进入修改的处理步骤中。 其他重要列属性介绍: 1)Visible属性,控制定义的列是否出现在显示的数据列表中。 2)AllowSorting属性,是否可以进行列排序。当AollowSorting=true时,可以以点击列的列表头的方式,把数据以该列次序进行排序。缺省的(即载入数据后)的排序方式,实际上是以数据在数据源中的排列次序进行排序的。 3)AllowPage属性,是否以分页方式显示数据。当对有大量数据的数据源进行显示时,可以以例如10行一页的方式来显示数据,同时显示一个下页/前页的按钮,按下按钮可以以向前或向后的方式浏览整个数据源的数据。当AllowPage=true时,即以分页方式进行显示。可以通过设定CurrentPageIndex属性来直接跳转到相应的数据页。 例子:演示以上各种类型的列定义的用法 1.源程序(formDataGrid.aspx) <!--源文件:form\ServerControl\formDataGrid.aspx--> <%@ Import Namespace="System.Data" %> <html> <script language="VB" runat="server"> dim Order as DataTable dim OrderView as DataView '对数据表格1创建数据表,并返回数据视图 Function LoadData() As ICollection Dim dt As DataTable Dim dr As DataRow Dim i As Integer '创建数据表 dt = New DataTable dt.Columns.Add(New DataColumn("Num", GetType(Integer))) dt.Columns.Add(New DataColumn("Name", GetType(String))) dt.Columns.Add(New DataColumn("DtTm", GetType(DateTime))) dt.Columns.Add(New DataColumn("Assembly", GetType(Boolean))) dt.Columns.Add(new DataColumn("Price", GetType(Double))) '载入数据 For i = 1 To 6 dr = dt.NewRow() dr(0) = i dr(1) = "书名 " + i.ToString() dr(2) = DateTime.Now.ToShortTimeString If (i Mod 2 <> 0) Then dr(3) = True Else dr(3) = False End If dr(4) = 1.11 * i '把产生的数据加入数据表中 dt.Rows.Add(dr) Next LoadData = New DataView(dt) End Function '页面初始化,分别对DataGrid1和DataGrid2绑定数据源 Sub Page_Load(sender As Object, e As EventArgs) If Session("session_order") = Nothing Then Order = New DataTable() Order.Columns.Add(new DataColumn("Name", GetType(string))) Order.Columns.Add(new DataColumn("Price", GetType(string))) Session("session_order") = Order Else Order = Session("session_order") End If OrderView = New DataView(Order) DataGrid2.DataSource = OrderView DataGrid2.DataBind If Not IsPostBack Then DataGrid1.DataSource = LoadData() DataGrid1.DataBind End If End Sub '对ButtonColumns的处理函数集合 Sub Grid_Command(sender As Object, e As DataGridCommandEventArgs) Dim dr As DataRow = order.NewRow() Dim Cell1 As TableCell = e.Item.Cells(3) Dim Cell2 As TableCell = e.Item.Cells(6) Dim name As String = Cell1.Text Dim price As String = Cell2.Text If e.CommandSource.CommandName = "Add" Then dr(0) = name dr(1) = price order.Rows.Add(dr) Else OrderView.RowFilter = "name='" & name & "'" If OrderView.Count > 0 Then OrderView.Delete(0) End If OrderView.RowFilter = "" End If DataGrid2.DataBind() End Sub </script> <head> <title> 数据表格实验 </title> </head> <body> <center> <h2>数据表格列类型实验</h2> <hr> <p></p> <form runat=server> <h3><b>图书清单</b></h3> <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" AutoGenerateColumns="false" OnItemCommand="Grid_Command"> <property name="Columns"> <!-- 2个ButtonColumn示例--> <asp:ButtonColumn HeaderText="操作" Text="订购" CommandName="Add" /> <asp:ButtonColumn HeaderText="操作" Text="退订" CommandName="Remove" /> <!-- HyperLinkColumn示例 --> <asp:HyperLinkColumn HeaderText="链接" DataNavigateUrlField="Num" DataNavigateUrlformatString="formDataGrid01.aspx?id={0}" DataTextField="Num" Target="_new" /> <!-- 2个标准BoundColumn示例 --> <asp:BoundColumn HeaderText="书 名" DataField="Name" /> <asp:BoundColumn HeaderText="入库时间" DataField="DtTm"/> <! -- 1个TemplateColumn示例 ,以CheckBox来表示布尔型数据 --> <asp:TemplateColumn HeaderText="合 集"> <template name="ItemTemplate"> <asp:CheckBox ID=Chk1 Checked='<%# DataBinder.Eval(Container.DataItem, "Assembly") %>' Enabled="false" runat="server" /> </template> </asp:TemplateColumn> <asp:BoundColumn HeaderText="价 格" DataField="Price" DataformatString="{0:c}" Itemstyle-HorizontalAlign="right" /> </property> </asp:DataGrid> <hr> <h3><b>订购清单</b></h3> <ASP:DataGrid id="DataGrid2" runat="server" BorderColor="black" BorderWidth="1" CellPadding="3" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#aaaadd" /> </form> </center> </body> </html> 文件formDataGrid01.aspx的内容: <!--源文件:form\ServerControl\formDataGrid01.aspx--> <html> <head> <title> 数据表格链接测试实验 </title> <script language="VB" runat="server"> Dim num As String Sub Page_Load(sender As Object, e As EventArgs) num=Request.QueryString("id") End Sub </script> </head> <body bgcolor=#ccccff> <center> <h2>数据表格链接测试结果画面</h2> <hr> <p></p> <h4>您选择的是 第<u> <%= num %></u>本藏书</h4> </body> </html> 2.开始时画面: 3.当选择订购了第一本和第三本后的画面如下: 4.当选择退订第三本书后的画面如下: 5.当点击连接第六项时的画面如下: 2.2.16 小结 本章主要讲述了几个服务器端的控件、它们的校验、取值方法等,从中我们可以看到asp.net中各种控件功能是非常强大的,如上面的例子所示,我们甚至可以用一个简单的语句就可以验证输入的合法性。对取值,我们也有简单的方法,对比于用html所写的代码,我们觉得用asp.net所写的是简单了很多。 第三章 自定义控件 asp.net中提供的增加内嵌服务器控件的功能,使你能够多次的轻松增加你所定义的各种控件。事实上,对于表单等各种控件,可以不用更改或者稍微更改一下就可以多次使用的。在通常情况下,我们把一个用作服务器控件的web表单统称为用户控件,我们用一个.ascx为后缀的文件保存起来,这样的保存使得它不被当作一个web表单来运行,当我们在一个.aspx文件中使用它时,我们用Register方法来进行调用,假设我们有一个文件名为saidy.ascx的文件,我们用下面的语句来调用它: <%@ Register TagPrefix="Acme" TagName="Message" Src="saidy.ascx" %> 上面的TagPrefix标记为用户控件确定个唯一的名字空间,TagName为用户控件确定一个唯一的名称,你也可以用其它的名字代替“Message“,Src为确定所包含的文件名称和路径。这样,我们就可以用下面的语句来调用它了: <Acme:Message runat="server"/> 下面我们来看看具体的应用 2.3.1 小页面控件 我们建立两个简单文件来说明这个控件的使用方法:con01.aspx、con01.ascx,在con01.ascx文件里我们只有一句话: <a href="http://www.yesky.com">欢迎访问天极网站</a> 然后我们在文件con01.aspx里面进行注册: <%@ Register TagPrefix="saidy" TagName="info" Src="con01.ascx" %> 页面上的应用我们用这句话来表达: <saidy:info runat="server"/> con01.aspx文件的完整代码如下: <!--源文件:form\CustomControl\con01.aspx--> <!--注册小页面控件--> <%@ Register TagPrefix="saidy" TagName="info" Src="con01.ascx" %> <html> <body> <BR><BR><BR> <CENTER> 调用结果 <BR><BR> <saidy:info runat="server"/> </CENTER> <BR><BR> </body> </html> 下面我们访问con01.aspx,显示如下: 2.3.2 代码和模板的分离 在编制asp.net程序时,我们会使用模板(Template)。那么什么是模板呢?相信大家都使用过WORD,当我们在新建一个WORD文件的时候,我们可以建立模板。通过使用模板,我们就固定了文档的风格,这样就可以在模板上完善我们的内容。所以我们使用模板一个好处是:文字录入和编排界面是分开的。而且模板可以重复使用。好了,通过上面的介绍,我们对模板就有了一定的认识。 我们在编制.NET程序时,使用模板将对主程序代码大大简化。模板的定义是使用<template>和</template>标示符的。文件保存为.ascx文件。下面的代码是一个典型的模板的定义。 <template name="itemtemplate"> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td valign="top"> <b>所在系: </b><%# DataBinder.Eval(Container.DataItem, "dept") %><br> <b>姓名: </b><%# DataBinder.Eval(Container.DataItem, "name") %><br> <b>性别: </b><%# DataBinder.Eval(Container.DataItem, "sex") %><br> <b>年级: </b><%# DataBinder.Eval(Container.DataItem, "grade") %> </td> </tr> </table> </template> 在这一模板中,我们使用了数据绑定控件,关于数据绑定控件,请参阅其它章节。同时我们还定义了数据的显示方式。那么在主程序中如何调用呢?请看下面的代码: 1.<%@ Register TagPrefix="Acme" TagName="StuList" Src="form32.ascx" %> 2.<html> 3.<body style="font: 10pt verdana"> 4.<b><center><h3>模板示例</h3></center></b> 5.<form runat="server"> 6.<Acme: StuList runat="server"/> 7.</form> 8.</body> 9.</html> 其实,模板也属于自定义控件(User Control),所以我们在使用时,要先注册(Register)。对主程序的第一行代码,TagPrefix定义了一个不重复的名字空间(Name Space)。TagName为自定义控件定义了一个名称。然后,我们就要指明使用的模板的文件名。注册完自定义控件后,我们就可以把此控件认为是服务器端控件。要使用服务器端控件,我们要做什么工作呢?对了,要使用runat=”server”属性了。请参考第7行代码。 好了,现在我们就看一个完整的例子!这个例子包含了两个文件,一个主程序文件(template.aspx),另一个是用户自定义控件文件(template.ascx)。先看template.aspx文件。 <!--源文件:form\CustomControl\template.aspx--> <%@ Register TagPrefix="Acme" TagName="stuList" Src="zy.ascx" %> <html> <body style="font: 10pt verdana"> <b><center><h3>模板示例</h3></center></b> <form runat="server"> <Acme:stuList runat="server"/> </form> </body> </html> 现在我们再来看template.ascx: <!--源文件:form\CustomControl\template.ascx--> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) If Not (Page.IsPostBack) Dim DS As DataSet Dim MyConnection As SQLConnection Dim MyCommand As SQLDataSetCommand MyConnection = New SQLConnection("server='iceberg'uid=sa;pwd=;database=info") MyCommand = New SQLDataSetCommand("select * from infor where dept='" & Category.SelectedItem.value & "'", MyConnection) DS = New DataSet() MyCommand.FillDataSet(DS, "infor") MyDataList.DataSource = DS.Tables("infor").DefaultView MyDataList.DataBind() End If End Sub Sub Category_Select(Sender As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SQLConnection Dim MyCommand As SQLDataSetCommand MyConnection = New SQLConnection("server='iceberg'uid=sa;pwd=;database=info") MyCommand = New SQLDataSetCommand("select * from infor where dept='" & Category.SelectedItem.value & "'", MyConnection) DS = New DataSet() MyCommand.FillDataSet(DS, "infor") MyDataList.DataSource = DS.Tables("infor").DefaultView MyDataList.DataBind() End Sub </script> <table style="font: 10pt verdana"> <center> <tr> <center><td><b>请选择系名:</b></td></center> <td style="padding-left:15"> <center> <ASP:DropDownList AutoPostBack="true" id="Category" OnSelectedIndexChanged="Category_Select" runat="server"> <ASP:ListItem value="信息系">信息系</ASP:ListItem> <ASP:ListItem value="工程系">工程系</ASP:ListItem> <ASP:ListItem value="英语系">英语系</ASP:ListItem> </ASP:DropDownList></center> </td> </tr> </table> <ASP:DataList id="MyDataList" BorderWidth="0" RepeatColumns="2" runat="server"> <template name="itemtemplate"> <table cellpadding=10 style="font: 10pt verdana"> <tr> <td valign="top"> <b>所在系: </b><%# DataBinder.Eval(Container.DataItem, "dept") %><br> <b>姓名: </b><%# DataBinder.Eval(Container.DataItem, "name") %><br> <b>性别: </b><%# DataBinder.Eval(Container.DataItem, "sex") %><br> <b>年级: </b><%# DataBinder.Eval(Container.DataItem, "grade") %> </td> </tr> </center> </table> </template> </ASP:DataList> 运行的效果图如下: 这样,一个完整的例子就做好了!实现了代码和模板的分离。试一下吧! 2.3.3 自定义控件 在asp.net中,除了我们应用的服务端控件之外,我们还可以创建自己的服务端控件,这样的控件叫Pagelet。我们来介绍如何创建一个Pagelet,这个Pagelet的功能是在被访问时返回一个消息。 我们创建一个Pagelet,用来返回一个消息在客户端的浏览器上: Welcome.ascx: <!--源文件:form\CustomControl\welcome.ascx--> 欢迎来到我这里啊!!! 就这么简单,当然你也可以让它复杂一点。当一个Pagelet被创建后,我们就可以通过下面的记录指示来调用它: <% @ Register TagPrefix="wmessage" TagName="wname" Src="Welcome.ascx" %> TagPrefix为Pagelet指定一个唯一的名字空间,TagName是Pagelet的唯一名字,当然你也可以换成其他的不是”wname“的名称如:TagName="saidy"。Src属性是指指向Pagelet的虚拟路径。 一旦我们注册了Pagelet,我们就可以向用普通的空件一样来应用它: <wmessage:wname runat="server"/> 下面的例子示范了自定义的控件的应用(welcome.aspx): <!--源文件:form\CustomControl\welcome.aspx--> <%@ Register TagPrefix="wmessage" TagName="wname" Src="Welcome.ascx" %> <html> <title>自定义的控件</title> <h3>.NET->Pagelet</h3> <wmessage:wname runat="server"/> </body> </html> 客户端的访问如下: 2.3.4 组合控件 1.定义 以类组合形式把已有的控件编译后形成自己定制的控件。实际上组合控件在效果上与利用内置控件形成的用户自定义控件一样,不同处在于,用户自定义控件含有一个.ascx的纯文本控制文件,而组合控件则利用编译后的代码。 2.步骤 1.)重新定义从Control继承来的CreateChildControls方法。 2.)如果组合控件要保持于页面上,须完成System.Web.UI.INamingContainer 接口。 3.例子: 演示一个自定义控件,当选择不同按钮时显示不同内容。 1)控件定义 '文件名:form\CustomControl\formCustom.vb Option Strict Off Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Namespace test '定义类tryVB Public Class tryVB : Inherits Control : Implements INamingContainer '定义属性value,实为TextBox控件的Text属性 Public Property value As String Get Dim Ctrl As TextBox = Controls(1) Return Ctrl.text End Get Set Dim Ctrl As TextBox = Controls(1) Ctrl.Text = value End Set End Property Protected Overrides Sub CreateChildControls() '重载CreateChildControls方法 Me.Controls.Add(New LiteralControl("选择结果为: ")) Dim Box As New TextBox Box.Text = " " Me.Controls.Add(box) End Sub End Class End Namespace 2)定义控件的编译 :批处理文件form\CustomControl\formCustom.bat的内容: vbc /t:library /out:..\bin\testVB.dll /r:System.dll /r:System.Web.dll formCustom.vb 请注意把生成的testVB.dll放到正确的目录中,以便asp.net解释时能够找到相应的类。 3)自定义组合控件的使用 <!--源文件:form\CustomControl\formcustom.aspx--> <%@ Register TagPrefix="test" Namespace="test" %> <!--首先注册test命名空间--> <html> <script language="VB" runat=server> Private Sub LeftBtn_Click(Sender As Object, E As EventArgs) '当选择左边的按钮时的显示 CustControl.value = "您选择的是Yes按钮" End Sub Private Sub RightBtn_Click(Sender As Object, E As EventArgs) '当选择右边的按钮时的显示 CustControl.value = "您选择的是No按钮" End Sub </script> <body> <center> <form method="POST" action="formcustom.aspx" runat=server> <!--引用自定义的组合控件tryVB--> <test:tryVB id="CustControl" runat=server/> <br> <!--画两个按钮供选择--> <asp:button text="是[Yes]" onClick="LeftBtn_Click" runat=server/> <asp:button text="否[No]" onClick="RightBtn_Click" runat=server/> </form> </center> </body> </html> 输出结果: 2.3.5 继承控件 在学习了微软公司的.NET平台为我们提供的大量功能强大的服务器端控件的使用方法以后,随着应用的深入,一些新的问题又出现了。首先是虽然有着大量的控制灵活的控件,但是否就真的满足了我们所有的需求?有时候,我们需要某种控件部分功能,又希望不要费太大的力气去实现,是否可以利用现有的控件来实现。再则,我们希望对某种控件进行改造,使它具有自己所希望的外形或者结果,而不是它缺省的方式运行。最后我们是否可以把自己经常用到的逻辑规则或者是应用界面作成用户控件,然后使用它就如同使用服务器控件那样方便。 其实以上三个问题,在现代面向对象设计方法中,是可以找到答案的。为最大可能的利用现有的开发成果,我们使用“继承”这一手段来节省开发的费用。光有继承不足以形成自己的应用,我们还可以利用“重载”和“多态”来形成自己的应用特点,使之区别于被继承的对象。为了使应用更加简洁和对外隐藏内部的实现、进一步实现代码重用,我们又使用了“封装”。 微软的.NET平台是支持面向对象的设计方式的新型平台,所以支持并且鼓励用户在应用中设计和使用自己定义的控件。设计用户自己的控件就如同上面所述,有如下步骤: 1.从System.Web.UI.Control类继承,并形成自己的类 为继承Control类,我们需引用System、System.Web、System.Web.UI类库,在vb环境下使用标识Imports来引入。为方便使用,我们还需定义一个命名空间以容纳多个类。在vb环境中使用Namespace 空间名和End Namespace标识对来定义一个命名空间。定义一个类使用Class ClassName和End Class标识对。为表明类之间的继承关系,可以使用Inherits标识。 继承控件的类定义框架定义如下: Imports System Imports System.Web Imports System.Web.UI Namespace MyNamespace Public Class MyClass:Inherits Control … End Class End Namespace 一个最简单的例子是从Control继承一个类,然后重载其Render方法。调用其Render方法即在页面以h2字体写出一行字。 Imports System Imports System.Web Imports System.Web.UI Namespace MyNamespace Public Class MyClass:Inherits Control Protect overrides Sub Render(OutPut as HtmlTextWriter) OutPut.Write(“<h2>这是一个最简单的控件继承例子!</h2>”) End Sub End Class End Namespace 2.定义自己的属性和方法,包括重载一些初始化的方法。 在vb中,以标识overrides指明该方法是一个重载函数。例如上面所举的Render方法:Protect overrides Sub Render(Output as HtmlTextWriter) 属性定义就较为复杂一点,首先是定义内部变量,可以为Public或者是Private,当为Public时可以被外部直接存取,这种方式面向对象方法并不提倡,为Private时,不能直接被外部存取,只有通过内部提供的属性定义方式来存取;然后对需要提供给外部使用的内部变量进行属性存取方式定义。在vb中使用Property 属性名 As 类型和End Property标识对来定义,Get/End Get标识对间定义如何通过属性取得内部变量的值,Set/End Set标识对间定义如何设置内部变量值。 例如:描述一个人的帐号信息,大致需要设定帐号(AcctNo)、身份证号(IdNo)、余额(Balance)、有效状态(Stat) Imports System Imports System.Web Imports System.Web.UI Namespace MyNamespace ‘定义一个枚举变量,0—正常 1—销户 2—其他状态(挂失、冻结等等) Public Enum Status Active = 0 Deactive = 1 Other = 2 End Enum Public Class Account : Inherits Control Private _AcctNo As String Private _IdNo As String Private _Balance As Currency Private _Stat As Status Public Property AcctNo As String Get Return _AcctNo End Get Set _AcctNo = value End Set End Property Public Property IdNo As String Get Return _IdNo End Get Set _IdNo = value End Set End Property Public Property Balance As Currency Get Return _Balance End Get Set _Balance = value End Set End Property Public Property Stat As Status Get Return _Stat End Get Set _Stat = value End Set End Property … End Class End Namespace 而方法的定义就比较灵活,可以根据设计要求,提供相应的功能,例如大多数的类一般都会提供创建或者是初始化类的方法。我们仍以上面的帐号类为例,定义一个New方法: 。。。 Public Sub New(AcctNo1 As String,IdNo1 As String,Balance1 As Currency,Stat1 As Status) MyBase.New Me.AcctNo = AcctNo1 Me.IdNo = IdNo1 Me.Balance = Balance1 Me.Stat = Stat1 End Sub 。。。 3.定义自己应用界面 一个用户自定义的控件一般来说较为复杂,由至少一个以上的内置控件构成,这时就需要重载从Control类继承来的CreateChildControls方法,并在其中生成界面控件。如果用户定义的控件会在一个页面中反复使用,最好implements System.Web.UI.INamingContainer,它会为该控件创建一个唯一的命名空间。 例如:下面的例子将创建一个控件,它由一段说明文字和一个文本输入框构成。 Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Namespace MyNamespace Public Class Myclass :Inherits Control : Implements INamingContainer … Protected Overrides Sub CreateChildControls() Me.Controls.Add(New LiteralControl("<h3>请输入: ")) Dim txtBox As New TextBox txtBox.Text = "" Me.Controls.Add(txtBox) Me.Controls.Add(New LiteralControl("</h3>")) End Sub … End Class End Namespace 4.定义自己控件的消息处理函数。 自己定义的控件含有两种类型的消息,一是包含的子控件所产生的消息,二是自定义的控件消息。 子控件产生的消息处理函数可由AddHandler函数来指定,其用法如下: AddHandler 子控件.消息,AddressOf 消息处理函数 例如:自定义控件中含有一个Button控件,并定义其处理函数MyBtn_Click() … Private Sub MyBtn_Click(Sender as Objects, E as EventArgs) … End Sub Protected override Sub CreateChildControls() … Dim MyBtn As New Button MyBtn.text=”” AddHandler MyBtn.Click , AddressOf MyBtn_Click Me.Controls.Add(MyBtn) … End Sub 自定义的控件消息则需要先定义事件说明,格式如下 Public Event 消息名(Sender as Object,E as EventArgs) 例如:Public Event Change(Sender as Object,E as EventArgs) 然后定义事件发出函数,例如: Protected Sub OnChange(E as EventArgs) RaiseEvent Change(Me,E) End Sub 再然后定义引起事件发生的过程(可不写) 例如: Private Sub TextBox_Change(Sender As Object, E As EventArgs) OnChange(EventArgs.Empty) End Sub 最后定义何时触发事件函数,同样使用AddHandler函数 例如: … Protected override Sub CreateChildControls() … Dim MyBox as New TextBox MyBox.Text=”” AddHandler MyBox.TextChanged , AddressOf TextBox_Change Me.Controls.Add(MyBox) … End Sub … 5.最后,谈一谈继承控件的使用,首先应把预先写好的继承控件编译成.DLL文件 编译格式为: vbc /t:library /out:MyDll.dll /r:System.Web.dll MyVb.vb vbc为vb.net的编译器 /t:表示编译类型,library为链接库,exe为独立可执行文件 /out:指定输出文件名 /r:表示需要引用的DLL文件 MyVb.vb:指自己编写的继承控件vb源程序 然后,为在自己的页面中引用自己定义的控件,需在aspx文件头进行注册, <%@ Register TagPrefix="标记前缀" Namespace="命名控件" %> 最后,就如同使用内置控件一样,在页面中使用自己定义的控件: <命名空间名:类名 …… runat=server /> 下面举一个具体的例子来说明: 我们仍然以开始定义的用户帐号为例来定义一个继承控件,该类有4个属性分别为客户帐号、身份证号、帐户余额、帐户状态,其用户界面设定为4个文本框供输入属性值以供修改,另外加2个按钮以供确认,同时为该控件设定一个事件Click,当按下确认键后,修改控件属性值,并且在页面中显示自定义控件的属性值,以确认事件确实生效了。 1.控件定义文件 '文件名:form\CustomControl\Inherit.vb Option Strict Off Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Namespace MyNamespace Public Enum Status Active = 0 Deactive = 1 Other = 2 End Enum ASP.NET完全入门(6)2.1.3.3 页面处理内部过程
我们来看看页面处理的内部过程。下面的过程是依次进行的: 2.1.3.3.1 Page_load 首先,页面的状态被恢复,然后触发Page_OnLoad事件。在这个过程中,你可以读取或者重置页面的属性和控件的属性,根据IsPostBack属性判定页面是否为第一次被请求,执行数据绑定,等等。 现在我们通过一个具体的例子,来详细讲述Page_load事件: 我们所做的这个例子关于用户登录的。 我们先来看page.aspx的代码: <!--源文件:form\web页面简介\page.aspx--> <%@ Register TagPrefix="Acme" TagName="Login" Src="page.ascx" %> <html> <title>登录演示</title> <script language="VB" runat="server"> Sub Page_Load(Sender As Object, E As EventArgs) If (Page.IsPostBack) MyLabel.Text &= "用户名:" & MyLogin.UserId & "<br>" MyLabel.Text &= "密码: " & MyLogin.Password & "<br>" End If End Sub </script> <body style="font: 10pt verdana"> <center> <h3>登录</h3></center> <form runat="server"> <Acme:Login id="MyLogin" UserId="" Password="" BackColor="beige" runat="server"/> </form> <asp:Label id="MyLabel" runat="server"/> </body> </html> 在这个文件中,我们使用了Page_OnLoad事件的IsPostBack属性,用来显示用户登录时的用户名和密码。 在来看一下page.ascx文件: <!--源文件:form\web页面简介\page.ascx--> <script language="VB" runat="server"> Public BackColor As String = "white" Public Property UserId As String Get Return UserName.Text End Get Set UserName.Text = value End Set End Property Public Property Password As String Get Return Pass.Text End Get Set Pass.Text = value End Set End Property </script> <center> <table style="background-color:<%=BackColor%>;font: 10pt verdana;border-width:1; border-style:solid;border-color:black;" cellspacing=15> <tr> <td><b>用户名: </b></td> <td><ASP:TextBox id="UserName" runat="server"/></td> </tr> <tr> <td><b>密码: </b></td> <td><ASP:TextBox id="Pass" TextMode="Password" runat="server"/></td> </tr> <tr> <td></td> <td><ASP:Button Text="提交" runat="server"/></td> </tr> </table> </center> 在这个文件中,我们设置了控件的属性。使之能在page.aspx中调用. 在下一个例子中,我们将使用Page_OnLoad事件,来执行数据绑定:
文件databind.aspx代码如下: <!--源文件:form\web页面简介\databind.aspx--> <html> <head> <title>数据绑定演示</title> <script language="VB" runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Not IsPostBack Then Dim values as ArrayList= new ArrayList() values.Add ("北京") values.Add ("上海") values.Add ("杭州") values.Add ("成都") values.Add ("重庆") values.Add ("西安") DropDown1.DataSource = values DropDown1.DataBind End If End Sub ‘定义按钮的单击事件 Sub SubmitBtn_Click(sender As Object, e As EventArgs) ’结果显示 Label1.Text = "你选择的城市是: " + DropDown1.SelectedItem.Text End Sub </script> </head> <body> <center><h3><font face="Verdana">数据绑定演示</font></h3></center> <form runat=server> <center><asp:DropDownList id="DropDown1" runat="server" /></center> <center><asp:button Text="提交" onClick="SubmitBtn_Click" runat=server/></center> <p> <center><asp:Label id=Label1 font-name="Verdana" font-size="10pt" runat="server" /></center> </form> <body> </html> 在下面的例子中,我们将用page_load事件来对数据库进行连接:
我们还要说明的是如果使用SQL语句对数据库进行操作的时候,就需要在页面中导入System.Data 和 System.Data.SQL 名字控件,文件pagedata.aspx的代码如下: <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> 程序代码如下(pagedata.aspx): <!--源文件:form\web页面简介\pagedata.aspx--> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SQL" %> <html> <script language="VB" runat="server"> Sub Page_Load(Src As Object, E As EventArgs) Dim DS As DataSet Dim MyConnection As SQLConnection Dim MyCommand As SQLDataSetCommand ‘同数据库进行连接,采用sql server数据库 MyConnection = New SQLConnection("server='iceberg'uid=sa;pwd=;database=info") ‘执行SQL操作 MyCommand = New SQLDataSetCommand("select * from infor",MyConnection) DS = New DataSet() MyCommand.FillDataSet(ds, "infor") MyDataGrid.DataSource=ds.Tables("infor").DefaultView MyDataGrid.DataBind() End Sub </script> <center> <body> <h3><font face="Verdana">Page_load事件演示</font></h3> <ASP:DataGrid id="MyDataGrid" runat="server" Width="600" BackColor="white" BorderColor="black" ShowFooter="false" CellPadding=3 CellSpacing="0" Font-Name="Verdana" Font-Size="8pt" Headerstyle-BackColor="#aaaadd" MaintainState="false" /> /body> </center> </html> 在这个程序中,我们在page_load事件中,我们做了哪些事呢? ① 与数据库连接。在这个例子中,我们使用SQL Server作为后台数据库。在这个库中,我们建立了info数据库,在数据库中有一张infor表。 ② 执行SQL操作 ③ 将筛选后的数据显示出来 2.1.3.3.2 事件处理
这一阶段处理表单的事件。你可以处理特定的事件,也可以在表单需要校验的情况下,根据IsValid属性判定页面的输入是否有效。 Web form提供了一些具有验证功能的服务器控件。这些控件提供了一套简单易用并且很强大的功能能检查输入时是否有错误。而且,还能显示提示信息给用户。 对于每个控件来说,都有一特定的属性,来验证输入的值是否有效。我们来看一下对输入控件需要验证的属性: 控件 需要验证的属性 HtmlInputText value HtmlTextAreaHtm value HtmlSelect value HtmlInputFile value TextBox Text ListBox SelectedItem DropDownList SelectedItem RadioButtonList SelectedItem 好了,有了上面的介绍,我们就以例子来讲解表单的有效性验证。 在下面一个简单的例子中,我们将对用户的输入验证。 如Validate.aspx 的内容如下: <!--源文件:form\web页面简介\validate.aspx--> <html> <head> <script language="VB" runat="server"> Sub ValidateBtn_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "页面有效!" Else lblOutput.Text = "在页面中不能出现空项!" End If ‘判断是否输入为数字 if not isnumeric(TextBox1.text) then lbloutput.text="请输入数值!" End if End Sub </script> </head> <body> <center><h3><font face="Verdana">验证表单的例子</font></h3></center> <p> <form runat="server"> <title>表单验证</title> <center> <table bgcolor="white" cellpadding=10> <tr valign="top"> <td colspan=3> <asp:Label ID="lblOutput" Text="请填写下面的内容" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server /><br> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>储蓄卡类型:</font> </td> <td> <ASP:RadioButtonList id=RadioButtonList1 RepeatLayout="Flow" runat=server> <asp:ListItem>绿卡</asp:ListItem> <asp:ListItem>牡丹卡</asp:ListItem> </ASP:RadioButtonList> </td> <td align=middle rowspan=1> <asp:RequiredFieldValidator id="RequiredFieldValidator1" ControlToValidate="RadioButtonList1" Display="Static" Initialvalue="" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>卡号:</font> </td> <td> <ASP:TextBox id=TextBox1 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator2" ControlToValidate="TextBox1" Display="Static" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <td> </tr> <tr> <td></td> <td> <ASP:Button id=Button1 text="验证" onClick="ValidateBtn_Click" runat=server /> </td> <td></td> </tr> </table> </center> </form> </body> </html> 我们对验证按钮的onClick事件进行编程,其中用到了IsNumeric()函数,用来判断变量是否为数值型的。我们还可以用IsData()函数对输入的日期进行判断。IsData()接受的合法日期为100年1月1日到9999年12月31日。 在这个程序中,仅仅作了一个简单的判断
Validate1.aspx的文件内容如下: <!--源文件:form\web页面简介\validate1.aspx--> <html> <head> <script language="VB" runat="server"> Sub ValidateBtn_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "页面有效!" Else lblOutput.Text = "在页面中不能出现空项!" End If If not isnumeric(TextBox1.text) then bloutput.text="请输入数值!" End if ‘在这里我们只作了一个简单的判断。使用了left $()函数 if left $(textbox1.text,2)<>"11" then lbloutput.text="请验证你的身份证输入" End if End Sub </script> </head> <body> <center><h3><font face="Verdana">验证表单的例子</font></h3></center> <p> <form runat="server"> <title>表单验证</title> <center> <table bgcolor="white" cellpadding=10> <tr valign="top"> <td colspan=3> <asp:Label ID="lblOutput" Text="请填写下面的内容" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server /><br> </td> </tr> <tr> <td align=right> <font face=Verdana size=2>身份证号:</font> </td> <td> <ASP:TextBox id=TextBox1 runat=server /> </td> <td> <asp:RequiredFieldValidator id="RequiredFieldValidator2" ControlToValidate="TextBox1" Display="Static" Width="100%" runat=server> * </asp:RequiredFieldValidator> </td> </tr> <td> </tr> <tr> <td></td> <td> <ASP:Button id=Button1 text="验证" onClick="ValidateBtn_Click" runat=server /> </td> <td></td> </tr> </table> </center> </form> </body> </html> 在这个程序中,我们仅对北京地区的身份证号进行了验证,我们使用Left $()函数把字符串的前两个字符取出进行比较。如果大家感兴趣的话,可以把这个程序补充完整。 我们在验证的时候,有时需要进行特殊的验证。在下面的表中,列出了需要进行特殊验证时要使用的特殊控件。 控件描述 RequiredFieldValidator使用户在输入时,不是使这一项为空 CompareValidator对两个控件的值进行比较 RangeValidator对输入的值进行控制,使其值界定在一定范围内 RegularExpressionValidator把用户输入的字符和自定义的表达式进行比较 CustomValidator自定义验证方式 ValidationSummary在一个页面中显示总的验证错误 现在对各个验证控件介绍: 1.RequiredFieldValidator 下面的这个例子,演示了RequiredFieldValidator控件的使用方法。 validate3.aspx文件: <!--源文件:form\web页面简介\validate3.aspx--> <html> <body> <center> <title>验证控件演示 (1)</title> <h3><font face="Verdana">验证控件演示 (1)</font></h3> <form runat=server> 姓名: <asp:TextBox id=Text1 runat="server"/> <asp:RequiredFieldValidator id="RequiredFieldValidator1" ControlToValidate="Text1" Font-Name="Arial" Font-Size="11" runat="server"> 此项不能为空! </asp:RequiredFieldValidator> <p> <asp:Button id="Button1" runat="server" Text="验证" /> </form> </center> </body> </html> 当我们不在文本框中输入内容的时候,页面上将会出现不能为空的提示。 程序运行如下: 2.CompareValidator 控件 为了比较两个控件的值,此时我们需要使用CompareValidator 控件。 在下面的这个例子中,我们将讲解CompareValidator 控件的用法。 先看文件validata4.aspx: <!--源文件:form\web页面简介\validate4.aspx--> <%@ Page clienttarget=downlevel %> <html> <title>CompareValidator控件示例</title> <head> <script language="VB" runat="server"> Sub Button1_OnSubmit(sender As Object, e As EventArgs) If Page.IsValid Then lblOutput.Text = "比较正确!" Else lblOutput.Text = "比较不正确!" End If End Sub Sub lstOperator_SelectedIndexChanged(sender As Object, e As EventArgs) comp1.Operator = lstOperator.SelectedIndex comp1.Validate End Sub </script> </head> <body> <center> <h3><font face="Verdana">CompareValidator控件示例</font></h3> <form runat=server> <table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td> <h5><font face="Verdana">字符串 1:</font></h5> <asp:TextBox Selected id="txtComp" runat="server"></asp:TextBox> </td> <td> <h5><font face="Verdana">比较运算符:</font></h5> <asp:ListBox id="lstOperator" OnSelectedIndexChanged="lstOperator_SelectedIndexChanged" runat="server"> <asp:ListItem Selected value="Equal" >=</asp:ListItem> <asp:ListItem value="NotEqual" ><></asp:ListItem> <asp:ListItem value="GreaterThan" >></asp:ListItem> <asp:ListItem value="GreaterThanEqual" >>=</asp:ListItem> <asp:ListItem value="LessThan" ><</asp:ListItem> <asp:ListItem value="LessThanEqual" >=<</asp:ListItem> </asp:ListBox> </td> <td> <h5><font face="Verdana">字符串 2:</font></h5> <asp:TextBox id="txtCompTo" runat="server"></asp:TextBox><p> <asp:Button runat=server Text="验证" ID="Button1" onclick="Button1_OnSubmit" /> </td> </tr> </table> <asp:CompareValidator id="comp1" ControlToValidate="txtComp" ControlToCompare = "txtCompTo" Type="String" runat="server"/> <br> <asp:Label ID="lblOutput" Font-Name="verdana" Font-Size="10pt" runat="server"/> </form> </center> </body> </html> 在上面的代码中,我们实现了对两个控件的值进行比较。 程序运行如下: 当我们在两个文本框中输入值,然后选定运算符后,点验证按钮后,在页面上将显示 比较结果:: 3.RangeValidator控件 RangeValidator控件主要界定输入的值的范围。因为有时我们要求输入的值是要有一定范围的,所以我们要使用RangeValidator来判断。 在下面的这个例子中,我们将来介绍RangeValidator控件。 请看validata5.aspx的程序内容: <!--源文件:form\web页面简介\validate5.aspx--> <%@ Page clienttarget=downlevel %> <html> <center> <title>RangeValidator控件演示</title> <head> <script language="VB" runat="server"> Sub Button1_Click(sender As Object, e As EventArgs) If (Page.IsValid) Then lblOutput.Text = "结果正确!" Else lblOutput.Text = "结果不正确!" End If End Sub Sub lstOperator_SelectedIndexChanged(sender As Object, e As EventArgs) rangeVal.Type = lstType.SelectedIndex rangeVal.Validate End Sub </script> </head> <body> <h3><font face="Verdana">RangeValidator控件演示</font></h3> <p> <form runat="server"> <table bgcolor="#eeeeee" cellpadding=10> <tr valign="top"> <td> <h5><font face="Verdana">输入要验证的值:</font></h5> <asp:TextBox Selected id="txtComp" runat="server"/> </td> <td> <h5><font face="Verdana">数据类型:</font></h5> <asp:DropDownList id="lstType" OnSelectedIndexChanged="lstOperator_SelectedIndexChanged" runat=server> <asp:ListItem Selected value="String" >String</asp:ListItem> <asp:ListItem value="Integer" >Integer</asp:ListItem> </asp:DropDownList> </td> <td> <h5><font face="Verdana">最小值:</font></h5> <asp:TextBox id="txtMin" runat="server" /> </td> <td> <h5><font face="Verdana">最大值:</font></h5> <asp:TextBox id="txtMax" runat="server" /><p> <asp:Button Text="验证" ID="Button1" onclick="Button1_Click" runat="server" /> </td> </tr> </table> <asp:RangeValidator id="rangeVal" Type="String" ControlToValidate="txtComp" MaximumControl="txtMax" MinimumControl="txtMin" runat="server"/> <br> <asp:Label id="lblOutput" Font-Name="verdana" Font-Size="10pt" runat="server" /> </form> </body> </center> </html> 当我们在三个文本框中分别输入要验证的值,最大值,和最小值,然后按下验证按钮,页面上将显示判断的结果。 在本例中我们只能比较integer和string的值,当然,我们也可以增加数据类型,如double型,float型,date型,currency型等。 结果运行如下: 4. RegularExpressionValidator控件 我们在制作网站的时候,尤其是各种电子商务网站,首先都会让用户填写一些表格来获取注册用户的各种信息,因为用户有可能输入各式各样的信息,而有些不符合要求的数据会给我们的后端ASP处理程序带来不必要的麻烦,甚至导致网站出现一些安全问题。因此我们在将这些信息保存到网站的数据库之前,要对这些用户所输入的信息进行数据的合法性校验,以便后面的程序可以安全顺利的执行。 ASP.NET完全入门(5)第二篇 WEB 页面 第一章 WEB 页面简介 2.1.1 WEB form 表单,英文单词是form,学习过VB的朋友一定不会陌生。在MS.NET架构里,form是一个经常使用到的词汇。比如:编写Windows 应用时会提到Windows form,编写Web 应用时会提到Web form。Windows form可以看作一个Windows窗体,这和在VB里面一样。而Web form则代表了一个一个的Web页面。总的看来,form就像是一个容纳各种控件的容器,各种控件都必须直接或者间接的和它有依存关系。form在这里译作“WEB表单”似乎有些不妥。“表单”这个词,在WEB程序员看来,总是和HTML里面的“form”相混淆。“WEB表单”似乎翻译成“WEB页面”更加妥当一些。 大家还记得VB里面的form实际上就是一个对象吧,它可以有自己的属性、方法、事件等等。WEB表单,或者说WEB页面,实际上是一个“对象” (Object)。MS.NET架构里面一个比较重要的概念就是“对象”:所有的控件都是对象,甚至数据类型都成了对象;每种数据类型都有自己特有的属性和方法。我们在后面的编程中将可以体会到。 WEB form的后缀名是ASPX。当一个浏览器第一次请求一个ASPX文件时,WEB form页面将被CLR(common language runtime)编译器编译。此后,当再有用户访问此页面的时候,由于ASPX页面已经被编译过,所以,CLR会直接执行编译过的代码。这和ASP的情况完全不同。ASP只支持VBScript和javascript这样的解释性的脚本语言。所以ASP页面是解释执行的。当用户发出请求后,无论是第一次,还是第一千次,ASP的页面都将被动态解释执行。而asp.net支持可编译的语言,包括VB.NET、C#、Jscript.NET等。所以,asp.net是一次编译多次执行。 为了简化程序员的工作,ASPX页面不需要手工编译,而是在页面被调用的时候,由CLR自行决定是否编译。一般来说,下面两种情况下,ASPX会被重新编译: 1.ASPX页面第一次被浏览器请求; 2.ASPX被改写 由于ASPX页面可以被编译,所以ASPX页面具有组件一样的性能。这就使得ASPX页面至少比同样功能的ASP页面快250%! 下面我们来看一下简单的WEB页面。 2.1.2 我的第一个Page 把下面的代码拷贝到myfirstpage.aspx文件中,然后从浏览器访问这个文件: <!--源文件:form\web页面简介\myfirstpage.aspx--> <form action="myfirstpage.aspx" method="post"> <h3> 姓名: <input id="name" type=text> 所在城市: <select id="city" size=1> <option>北京</option> <option>上海</option> <option>重庆</option> </select> <input type=submit value="查询"> </form> 你可能觉得这个页面太简单了,用HTML就可以完成。是的!微软建议你将所有的文件哪怕是纯HTML文件都保存为ASPX文件后缀,这样可以加快页面的访问效率!不仅仅是在asp.net环境中,在IIS5.0以后的ASP3.0就已经支持这个特性了。 由于我们没有对表单提交做任何响应,所以,当你按下“查询”按钮,页面的内容没有什么改变。 下面我们将逐步使用asp.net的思考方式,来完成我们的页面。 2.1.3 WEB页面处理过程 这一节我们将深入到asp.net内部,看看页面是怎样被处理的。 和所有的服务器端进程一样,当ASPX页面被客户端请求时,页面的服务器端代码被执行,执行结果被送回到浏览器端。这一点和ASP并没有太大的不同。 但是,asp.net的架构为我们做了许多别的事情。比如,它会自动处理浏览器的表单提交,把各个表单域的输入值变成对象的属性,使得我们可以像访问对象属性那样来访问客户的输入。它还把客户的点击映射到不同的服务器端事件。 了解WEB页面的处理过程很重要。这样你可以仔细地优化你的代码,提高代码的效率。 2.1.3.1 页面的一次往返处理 用户对Server Control的一次操作,就可能引起页面的一次往返处理:页面被提交到服务器端,执行响应的事件处理代码,重建页面,然后返回到客户端。 正因为每个Control都可能引发一次页面的服务器端事件,所以,asp.net尽量减少了控件的事件类型。很多组件都只有onClick事件。特别的,asp.net不支持服务器端的onMouseOver事件。因为onMouseOver事件发生得非常频繁。所以,支持服务器端的onMouseOver事件是非常不现实的。 2.1.3.2 页面重建 每一次页面被请求,或者页面事件被提交到服务器,asp.net运行环境将执行必要的代码,重建整个页面,把结果页面送到浏览器,然后抛弃页面的变量、控件的状态和属性等等页面信息。当下一次页面被处理时,asp.net运行环境是不知道它的上一次执行情况的。在这个意义上,ASPX页面是没有状态的。这也是HTTP协议的特点(为了加速页面的访问,在asp.net页面里面可以使用缓存机制,也就是保存页面的执行结果,下一次页面被请求时,直接送回上一次的执行结果。)。 在ASP中,当页面被提交到服务器端时,只有那些用户输入的值被传递到服务器。其他的比如组件的属性、变量的值,是不会传递的。所以服务器无法了解组件的进一步的信息。 在asp.net中,页面对象的属性、页面控件的属性被称为“view state”(页面状态)。页面状态在asp.net中被受到特别关照。请看服务器端(page1.aspx)的代码: <!--源文件:form\web页面简介\page1.aspx--> <HTML> <BODY> <SCRIPT language="VB" runat="server"> Sub Showvalues(Sender As Object, Args As EventArgs) divResult.innerText = "You selected '" _ & selOpSys.value & "' for machine '" _ & txtName.value & "'." End Sub </SCRIPT> <DIV id="divResult" runat="server"> </DIV> <form runat="server"> 机器名: <INPUT type="text" id="txtName" runat="server"> <P /> 操作系统: <select id="selOpSys" size="1" runat="server"> <OPTION>Windows 95</OPTION> <OPTION>Windows 98</OPTION> <OPTION>Windows NT4</OPTION> <OPTION>Windows 2000</OPTION> </SELECT> <P /> <INPUT type="submit" value="Submit" runat="server" onserverclick="Showvalues"> </form> </BODY> </HTML> 运行后将自动被解释成客户端代码,如下: <HTML> <BODY> You selected 'Windows 98' for machine 'iceberg'. <form name="ctrl0" method="post" action="pageone.aspx" id="ctrl0"> <INPUT type="hidden" name="__VIEWSTATE" value="a0z1741688109__x"> 机器名: <INPUT type="text" id="txtName" name="txtName" value="tizzy"> <P /> 操作系统: <SELECT id="selOpSys" size="1" name="selOpSys"> <OPTION value="Windows 95">Windows 95</OPTION> <OPTION selected value="Windows 98">Windows 98</OPTION> <OPTION value="Windows NT4">Windows NT4</OPTION> <OPTION value="Windows 2000">Windows 2000</OPTION> </SELECT> <P /> <INPUT type="submit" value="Submit"> </form> </BODY> </HTML> 对于上面的代码,服务器端控件能在服务器端脚本中被自由运用。如果我们用传统的ASP代码实现上述的功能的话: If Len(Request.form("selOpSys")) > 0 Then StrOpSys = Request.form("selOpSys") StrName = Request.form("txtName") Response.Write("You selected '" & strOpSys _ & "' for machine '" & strName & "'.") End If 如果我们用asp.net的话,程序代码如下: If Len(selOpSys.value) > 0 Then Response.Write("You selected '" & selOpSys.value _ & "' for machine '" & txtName.value & "'.") End If 通过上面例子不难看出:asp.net页面具有组件方式的方便性和灵活性。 请注意:asp.net通过把页面的状态封装到一个隐藏的输入域,从而可以在不同的页面之间实现传递页面的状态。 另外,asp.net也支持应用程序一级的状态管理。这个特性在ASP中就已经实现。 ASP.NET完全入门(2)上述功能将协同作用,以便大幅度地提高用户使用计算技术的生产效率。根据设计,.NET使得用户无需在如何与计算机进行交互上劳神,从而全身心地投入到使计算机自动执行任务、实现最终目标的工作中。通过使用XML行业标准,可将用户数据进行跨站点和应用程序的链接,从而轻松实现当前很难实现的操作。比如:对用户在数家不同银行、信用卡公司以及计费代理商那里的数据进行集中处理;这样,用户便可依据处理后的数据支付帐单,将费用明细报告归档。 .NET把雇员、客户和商务应用程序整和成一个协调的、能进行智能交互的整体,而各公司无疑将是这场效率和生产力革命的最大受益者。简言之,.NET承诺为人类创造一个消除任何沟鸿的商务世界。 1.1.2.3 MicroSoft .NET 的基本模块 u网络服务一览 通常说来,一个网络服务只是一个作为服务――通过Internet标准此服务能与其它 网络服务集成在一起――发行的简单的应用程序。换句话说,它是可通过URL定位的自动将信息返回到需要它的客户端那里的一种资源。网络服务一个重要的特点是客户不需要知道一种服务是怎样实现的。在本节中,我将向你解释网络及网络服务如何把基于组件技术的最好的方面结合在一起的,并且介绍与网络服务通信所需的基本框架。 同组件一样,网络服务提供“黑匣子”函数,它可以被再次作用而不用关心此服务是怎样实现的。网络服务提供被称为契约的精确定义的接口,此接口描绘了所提供的服务。开发人员可以将远程服务、本地服务和定置代码组合在一起而集成应用程序。例如,某公司可以使用如下服务组建一在线商店:微软护照(原文:Passport)服务以验证用户身份,第三方个人化服务以使网页匹配每一个用户的参数,信用卡处理服务,销售税服务,对每个运输公司的包裹跟踪服务,链接公司内部库存管理程序的内部目录服务,以及少量定置代码以使他们的商店能脱颖而出。 然而,网络服务与现在的组件技术不同,它不使用需要在服务器和客户机有明确的、同类型基本构架的具体的对象模型协议,例如DCOM、 RMI或 IIOP 。尽管与具体组件技术紧密结合的实现在一个受控的环境中能很好地被接受,但它们在网络环境中变得不切实际。因为一个集成商业程序的参与者会发生变化,随着时间的推移,技术也在变化,所以在所有参与者间确保一个单一的、统一的体系架构就变得十分困难。网络服务采取了另外一种途径,它使用普便存在的网络协议和数据格式,如HTTP和XML,进行通信。支持这些网络标准的任何系统都支持网络服务。 而且,网络服务契约描述的是以术语报文形式提供的服务,这些服务是由网络服务生成和接受的,而不是描述服务是如何实现的。通过把重点放在报文上,网络服务模板就完全对语言、平台和对象模板一无所知。 用任何一套编程语言、对象模型和平台的完全特性集,都可实现网络服务。网络 服务可在任何平台被用任何语言所实现的应用程序使用。只要用于解释服务容量、报文序列和所期望协议的契约得到认同,那么所实现的网络服务及网络服务用户就可相互不同,而不会影响会话另一端的应用程序。 网络服务模板对最小体系架构的要求很低,以确保网络服务在使用任何技术和编程语言的平台上实现和访问。对网络服务互用性的解决可只依靠网络标准。然而,为了使应用程序更容易使用网络服务,简单地同意通过标准网络协议就可以访问网络服务是不够的。当网络服务和网络服使用者依靠标准的方式表示数据和命令、表示网络服务契约 、算出网络服务所提供的容量时,网络服务才容易使用。 XML是定义一个标准的、可扩展的用于提供命令和典型数据的语言明显的一种选择。虽然为表示命令和典型数据可以定义使用其它技巧(比如编码为一种查询字符串)的规则,但XML被专门设计为描述数据的标准元语言。简单对象存取协议(SOAP)是以一种可扩展的方式使用XML表示数据和命令的工业标准。网络服务可选择用SOAP决定报文的格式。 XML是网络服务契约的一种使能技术。服务契约语言 (SCL)是记录网络服务契约的XML语法。由于SCL是基于XML的,所以对开发者和开发工具来说,容易生成、解释契约。关于SCL细则的草案很快会出台(注意:现在的SOAP Toolkit for Visual Studio 6.0支持称为SDL的SCL的早期版本)。 Disco 规范为服务提供者发布网络 服务契约和相应的机制描述了一个标准方式,这将使开发者或开发工具可找到契约文献。当你读到这里时, Disco规范的草案应出台了。 象SOAP, SCL和Disco这样的标准有助于开发者,因为它们不需要明白和实现所使用的每一个网络服务的访问方式。支持这些标准的更好的、已充分测试的、高性能的体系架构将由开发平台提供,这会大大简化整个开发过程。 uMicroSoft .NET Framework MicroSoft .NET框架的目的是使你更容易建立网络应用程序和网络服务。图2 显示了MicroSoft .NET框架的体系。建立在操作系统最上层的服务,是管理运行时代码需求的common language runtime,这些代码可以用任何现代编程语言所写。Runtime提供了许多服务,这些服务有助于简化代码开发和应用程序的开发同时也将提高应用程序的可靠性。.NET Framework包括一套可被开发者用于任何编程语言的类库。在此之上是许多应用程序模板,这些模板特定地为开发网络站点和网络服务提供高级组件和服务。 uCommon Language Runtime 运行语言(runtime)调入并运行用任何运行感知编程语言所写的代码。以运行为目标的代码被称为受控(managed )代码,受控代码代码只是意味着在内部可执行代码与运行自身间存在已定义好的合作契约。对于象生成对象、调用方法等这样的任务,被委托给了运行语言,这使得在运行语言能为可执行代码增加额外的服务。 运行语言以交叉语言集成、自描述组件、简单配制和版本化及集成安全服务为特点。 运行语言使用一种新的能表达大部分现代编程语言语义的通用类型系统,通用类型系统定义了一套标准类型及生成新标准的规则。运行语言知道怎样生成、执行这些类型。编译器和解释器使用运行语言服务定义类型、管理对象、进行方法调用,而不是使用工具或特定于语言的方法。 类型系统的主要设计目的是使多种语言能深度集成。用一种语言所写的代码能继承用另一种语言所写的类的实现,用一种语言所写的代码抛出的异常能被用另一种语言写的代码捕获,象调试和剖析之类的操作会在完全封闭下工作,而不用考虑代码所用的语言。这就意味着编写可重用类库的开发者,不再需要为每一种编程语言或编译器生成一个版本,并且使用类库的开发者不再受到为他们使用的编程语言开发的库的限制。 自描述组件――现在MicroSoft .NET框架上已成为可能――简化了开发和配制,并提高了系统的可靠性。许多由运行语言提供的服务是由元数据及用于补充可执行代码的信息所驱动。因为所有的信息都储存在一起,只有可执行的(代码)才被称为自描述组件。 自描述组件的一个主要优点是,使用它们并不需要其它文件。类的定义不需要单独的头文件;通过检查元数据对类的定义可以从组件自身获得。跨语言或过程边界访问组件并不需要各自的IDL文件、类型文件或proxy/stubs;所必需的信息已存在于元数据之中。为识别开发者请示的服务属性,并不需要展开各自的配制信息。 最主要的是,由于元数据是在编译过程中由源代码生成,并与可执行代码储存在一起,它将永远和可执行部分同步。 除了改善对单个组件的配制,Microsft .NET框架定义了一个应用程序配制模板,以解决定置应用程序安装和DLL版本化(通常被称为“DLL Hell”)这一复杂过程的问题,运行语言提供了支持这个模板的服务。 Microsft .NET框架 引入了组合体的概念。一个组合体是一组资源和类型,并包括有关这些资源和类型的元数据,也就是被作为一个单元配制的。元数据被称为组合体的名单,它包含象类型和资源表之类能被组合体外看得见的信息,这个名单也包括有关从属关系之类的信息,例如组合体建立时的版本号。开发人员可以指定版本策略,以指示运行语言是否装入系统上已安装的依赖于组合体的最新版本,装入一指定版本,或在编译时使用的版本。 某软件组件的多个拷贝总可以存在于同样的操作系统上,然而,通常说来,只有其中的一个拷贝能被操作系统注册、调入内存、执行。对系统来说,定位和调入内存的策略是全局性。.NET Framework Common Language Runtime 增加了所必须的体系架构以支持管理组件定位和调入的每个应用程序策略,这通常被称为并行配制。 组合体可以被一个应用程序私有,或被多个应用程序共享。一个组合体的多个版本可以同时配制在同一台机器上。应用程序配制信息定义了到何处去查找组合体,这样runtime就能为同时运行的两个不同的应用程序装入同一组合体的不同版本。这就消除了由组件版本的不兼容性引起的问题,提高了系统整体的稳定性。如果必要,如果必要,管理员可以为配制时刻的组合体增加配制信息,例如一个不同的版本策略,但是编译时提供的原始信息永远不会丢失。 因为组合体是自描述的,所以并不需要在系统上进行显式注册。应用程序的配制简单到只需将文件拷贝到目录中既可(如果为了使应用程序能够运行,必须安装未经组织过的组件的话,情况会稍微复杂一点)。配制信息保存在可被任何文本编辑器编辑的XML文件中。 最后,运行语言也提供完整的、普遍深入的安全服务,以确保未经授权的用户不能访问机器上的资源,并且代码不会执行未经允许的动作。这就提高了系统整体的安全性可靠性。 由于运行语言用于装入代码、生成对象、执行方法调用,所以当受控代码装入内存、执行时,运行语言能进行安全检查,强化安全策略。 Microsft .NET框架不仅规定代码访问安全,还规定基于角色的安全。通过代码访问安全机制,开发人员能为应用程序指定完成工作所必需的权限。例如,代码或许需要写文件或访问环境变量的权力。这类信息和有关代码标志的信息一起存储在配制级上的。当代码装入内存及执行方法调用时,运行语言验证是否能给予代码所要求的权限。如果不能,将记录一条安全冲突信息。给予权限的策略,这被称为信任策略,是由系统管理员建立的,并且是建立在关于代码的证据基础之上,比如:代码是谁发布的,是从什么地方获得的,以及在组合体中找到的代码标志和它要求的权限。开发人员可以指定他们显然不需要的权限,以防止其它人恶意使用他们的代码。如果所需要的权限依赖直到运行时刻才会知道的信息,那么就可写入纲邻性的安全检查。 除了代码访问安全,运行语言还支持基于角色的安全。基于角色的安全建立同代码访问安全一样的权限模板,只是这些权限是建立在用户的身份之上,而不是建立在代码的标志之上。角色表明了用户所属的类,并且可以在开发和配制阶段定义。给予权限的策略被分配到每个预定义的角色。在运行时刻,用户的身份被确定,代码将代表这个身份运行。运行语言决定用户是哪个角色的成员,然后给予基于这个角色的权限。 在查看Microsft .NET框架的可编程模板前,先看一下它所提供的服务。 l服务框架 在Common Language Runtime之上是服务框架,此框架提供能被任何现代编程语言调用的类。所有的类都遵循一套命名和设计方针,以大大减小开发人员的学习上的弯路。 框架包括一套开发人员希望在标准语言库中存在的基类库,例如:集合、输入/输出,字符串及数据类。另外,基类库提供访问操作系统服务如图画、网络、线程、全球化和加密的类。服务框架也包括数据访问类库,及开发工具,如调试和剖析服务,能够使用的类。本文章没有详细讨论所有的类,我将重点放在数据访问类上,因为大多数网络服务需要对数据的访问。当然,你可以在MicroSoft .NET Framework SDK中找到关于服务框架类库的附加信息。 l数据访问服务 几乎所有的网络服务都需要查询和更新永久性数据,不论是以简单文件,还是以相关数据库,或是以其它的存储类型存在。为了提供对数据的访问,服务框架包括ActiveX Data Objects+ (ADO.NET)类库。如同名子所暗示地那样,ADO.NET由ADO发展而来。ADO+被设计为基于网络的可扩展的应用程序和服务提供数据访问服务。ADO.NET为连接的指针风格的数据访问,同时也为更适合于把数据返回到客户端应用程序的无连接的数据模板提供高性能的APIs流,就象在以后介绍的那样。 就象其余几个部分一样,ADO.NET定义了那些链接数据仓库、 对数据仓库发送命令及从中获取结果的类。这些类由受控数据提供者(managed data provider)实现。ADO+中链接和命令对象看上去和ADO中的是一样的,并且一个名为DataReader的新类提供了通过高性能API流获取结果的能力。DataReader在功能上同前向、只读的ADO记录集(Recordset)是等同的,但是DataReader被设计用来最小化内存中生成的对象的数量,以提高性能,避免垃圾积累。在.NET Framework中包含了针对MicroSoft SQL Server™的受控数据提供者以及可通过OLE DB访问的任何数据仓库。 ADO.NET的一个主要创新是引入了数据集(Dataset)。一个数据集是内存中提供数据关系图的高速缓冲区。数据集对数据源一无所知,它们可以由程序或通过从数据仓库中调入数据而被生成、填充。不论数据从何处获取,数据集都是通过使用同样的程序模板而被操作的,并且它使用相同的潜在的数据缓冲区。使用.NET平台的开发人员能够用数据集代替传统ADO中无连接的记录集。 受控数据提供者为数据仓库和数据集公开一名为DataSetCommand 的接口对象。DataSetCommand 使用ADO.NET链接和命令以从数据仓库中填充数据集,并把在数据集中发生的变化解析到数据仓库中。 就象DataReaders 显示了对于相关数据的有效的流访问一样,XmlReaders 显示了对XML数据的流访问。开发人员使用DataNavigator 可以滚动和编辑内存中的XML文档。DataNavigator在功能上和W3C Document Object Model (DOM)是一样的,但它更有效,并提供了能很好映射关系数据表的对象模板。DataNavigator 支持Xpath语法以对数据流进行导航。ADO.NET为那些希望继续使用DOM作为XML对象模板而不是使用更有效的DataNavigator模板的开发人员提供了一个XMLDocument类。 由于所有的数据都可被看作XML,所以开发人员可以为任何数据使用转换和确认服务。ADO.NET定义了一个消费DataNavigator、生成一个新的XmlReader的通用转换体系。.NET Framework提供了一个支持W3C XSL Transformations (XSLT)细则的特殊转换组件。ADO.NET同时提供了一使用XML简图确认XmlReader的确认引擎。ADO.NET支持通过DTDs, XSD或 XDR定义的简图。 l表单应用模板 从概念上讲,在服务框架的最上面是两个应用程序模板:Windows应用程序模板和网络应用程序模板。尽管我把重点放在把微软.NET 框架用作开发网络服务和网络应用程序的一种途径上,但框架也可用于开发较传统的基于Windows的应用程序(当然,这些应用程序也能使用网络服务)。 编写Windows客户应用程序的开发人员可使用Win表单应用程序模板以利用Windows丰富的用户接口特点,包括现在的ActiveX控件和Windows 2000的新特点,如透明的、分层的、浮动窗口。可以选择传统的Windows或网络外观。得知它和现在的基于Windows表单包的相似性以后,开发人员会发现Win表单可编程模板和对设计阶段的支持非常直观。 Win 表单利用了Microsft .NET框架 runtime以减少基于Windows的客户应用程序的开销。只要应用程序和组件是用Win所写或被Win表单应用程序使用,那么它们就能被框架安全模板在客户机上安全地执行。如果以这种方式使用或执行,那么某人从Internet下载下来的生猛游戏就不会对配制信息和数据产生破坏,否则会自动地给用户地址薄里的每一个人发送电子邮件。 Microsft .NET框架 装配模板简化了应用程序的配制和版本化 。应用程序可被配制为使用它们在编译和测试所用的共享组件,而不是使用恰好在客户机器上安装的随便什么版本的组件,这就提高了应用程序的可靠性,减少了应用程序所支持调用的主要因素:用户接口控件和其它共享组件版本的不兼容性。 ASP.NET完全入门(1)第一篇 概论 第一章 微软.NET战略和ASP.NET简介 欢迎你阅读《ASP.NET完全入门》,通过对本书的阅读,我们相信你能够对ASP.NET会有更深入的了解。 ASP.NET又叫ASP+,但并不仅仅是ASP的简单升级,而是MicroSoft推出的新一代Active Server Pages脚本语言。ASP.NET是微软发展的新型体系结构.NET的一部分,它的全新技术架构会让每一个人的网络生活都变得更简单。 首先需要特别指出的是,ASP.NET不仅仅只是有了一个新界面并且修复了一些缺陷的ASP3.0的升级版本(即不同于ASP2.0升级到ASP3.0的转变)。更为重要的是,ASP.NET吸收了ASP以前版本的最大优点并参照Java、VB语言的开发优势加入了许多新的特色,同时也修正了以前的ASP版本的运行错误。 要了解ASP.NET的真实面目,我们首先就得了解一下微软.NET战略。 1.1.1 微软.NET的历史 随着网络经济的到来,微软公司希望帮助用户,能够在任何时候、任何地方、利用任何工具都可以获得网络上的信息,并享受网络通信所带来的快乐。.NET战略就是为着实现这样的目标而设立的。 微软公开宣布,今后将着重于网络服务和网络资源共享的开发工作,并称,将会为公众提供更加丰富、有用的网络资源与服务。 微软新一代平台的正式名称叫做“新一代Windows服务”(NGWS),现在微软已经给这个平台注册了正式的商标——MicroSoft.Net。在.Net环境中,微软不仅仅是平台和产品的开发者,并且还将作为架构服务提供商、应用程序提供商,开展全方位的Internet服务。在谈及这个平台中使用的新技术,微软透露,它将在.Net环境中提供更多新产品和一揽子的全套服务。 MicroSoft .NET平台的基本思想是: 侧重点从连接到互联网的单一网站或设备上,转移到计算机、设备和服务群组上,使其通力合作,提供更广泛更丰富的解决方案。用户将能够控制信息的传送方式、时间和内容。计算机、设备和服务将能够相辅相成,从而提供丰富的服务,而不是像孤岛那样,由用户提供唯一的集成。企业可以提供一种方式,允许用户将它们的产品和服务无缝地嵌入自己的电子构架中。这种思路将扩展二十世纪八十年代首先由PC赋予的个人权限。 MicroSoft .NET将开创互联网的新局面,基于HTML的显示信息将通过可编程的基于XML的信息得到增强。XML是经“万维网联盟”定义的受到广泛支持的行业标准,Web浏览器标准也是由该组织创建的。微软公司为开发它投入了大量精力,但它并不是MicroSoft的专有技术。XML提供了一种从数据的演示视图分离出实际数据的方式。这是新一代互联网的关键,提供了开启信息的方式,以便对信息进行组织、编程和编辑;可以更有效地将数据分布到不同的数字设备;允许各站点进行合作,提供一组可以相互作用的“Web服务”。 1.1.2 微软.NET的介绍 1.1.2.1 MicroSoft .NET综述 MicroSoft .NET平台包括用于创建和操作新一代服务的.NET基础结构和工具;可以启用大量客户机的.NET User Experience;用于建立新一代高度分布式的数以百万计的.NET积木式组件服务;以及用于启用新一代智能互联网设备的.NET设备软件。 MicroSoft .NET产品和服务—包括Windows.NET,连同建立积木式服务的核心集成套件;MSNTM .NET;个人订购服务;Office.NET;Visual Studio .NET;以及用于.NET的bCentralTM。 .Net环境中的突破性改进在于: 1.使用统一的Internet标准(如XML)将不同的系统对接; 2.这是Internet上首个大规模的高度分布式应用服务架构; 3.使用了一个名为“联盟”的管理程序,这个程序能全面管理平台中运行的服务程序,并且为它们提供强大的安全保护后台; .NET平台包括如下组件: 1.用户数据访问技术。其中包括一个新的基于XML的、以浏览器为组件的混合信息 架构,叫做“通用画板”; 2.基于Windows DNA 2000的构建和开发工具; 3.一系列模块化的服务,其中包括认证、信息传递、存储、搜索和软件送递功能; 4.一系列驱动客户设备的软件; 1.1.2.2 Microsoft.NET平台带来的重要意义 我们来看一下MicroSoft .NET对开发人员、IT专业人员、以及企业应用的巨大意义 。 l对于开发人员 MicroSoft .NET的策略是将互联网本身作为构建新一代操作系统的基础,对互联网和操作系统的设计思想进行合理延伸。这样,开发人员必将创建出摆脱设备硬件束缚的应用程序,以便轻松实现互联网连接。MicroSoft .NET无疑是当今计算机技术通向计算时代的一个非常重要的里程碑。 .NET的核心组件有: · 一组用于创建互联网操作系统的构建块,其中包括Passport.NET(用于用户认证)以及用于文件存储的服务、用户首选项管理、日历管理以及众多的其它任务 · 构建和管理新一代服务的基本结构和工具,包括Visual Studio.NET、.NET企业服务器、.NET框架和Windows.NET · 能够启用新型智能互联网设备的.NET设备软件 · .NET用户体验 .NET对最终用户来说非常重要,因为计算机的功能将会得到大幅度提升,同时计算机操作也会变得非常简单。特别地,用户将完全摆脱人为的硬件束缚:用户可以自由冲浪于互联网的多维时空,而不是束缚在便携式电脑的方寸空间——可通过任何桌面系统、任何便携式电脑、任何移动电话或PDA进行访问,并可对其进行跨应用程序的集成。 .NET可使用户轻松进行互联网连接,并轻松完成那些在当今看来十分费时而且费力的事务,它们往往要求用户进行数据重输入并需运行几个小时才能完成。通过将多项安全数据流合并到单一的用户界面(或者甚至是可编程决策引擎),.NET架构将用户从充斥于当今Web的数据竖井的束缚中解脱出来。用户可以自由访问、自由查看、自由使用他们的数据。 .NET对开发人员来说也十分重要,因为它不但会改变开发人员的开发应用程序的方式,而且使得开发人员能创建出全新的各种应用程序。新型开发范例的核心是Web服务这个概念的引入。Web服务是一种通过简单对象访问协议(SOAP),在互联网上展露其功能性的、极为公开的服务。SOAP是一种基于可扩展标记语言(XML)制定的协议。 在过去,开发人员通过集成本地系统服务来构建应用程序。在这种模型下,开发人员可以访问丰富的开发资源并能严格控制应用程序的行为。 如今,开发人员已在很大程度上挣脱了这种模型的束缚,致力于构建具有复杂结构的n层化系统,这种系统能将网络上众多的应用程序一并进行集成,大大提升了应用程序的价值。这样,开发人员便可把精力集中在充分挖掘软件独特的商业价值,而不是构建基本结构上。可喜的局面将应运而生:软件投放市场的时间大大缩短、开发人员的编程效率明显提高,最终把质量上乘的软件呈现给用户。 我们正在进入一个崭新的计算时代——一个由互联网(尤其是Internet核心技术XML)实现的时代。利用XML,能够创建出可供任何人从任何地方使用的、功能非常强大的应用程序。它极大地拓展了应用程序的功能,并实现了软件的动态提供。在这种情况下,软件已不完全指那些从光盘进行安装的程序,而是演变成了一种服务——类似于ID调用程序或按收看次数进行收费的电视——人们可通过通信媒体订购的服务。 n层计算技术具有能够大幅度提高生产力、紧密耦合的特点,而Web概念具有面向消息、松散耦合的特点,我们将二者有机地糅合在一起,实现了上述构想。我们将这种计算风格称为Web服务,它的出现标志着人类已经迈入应用程序开发技术的新纪元。Web服务是一种应用程序,它可以通过编程并使用标准的Internet协议,像超文本传输协议(HTTP)和XML,将功能展示在互联网和企业内部网上。还可将Web服务视作Web上的组件编程。 从理论上讲,开发人员可通过调用Web应用编程接口(API),将Web服务集成到应用程序中。其调用方法与调用本地服务类似,不同的是Web API调用可通过互联网发送给位于远程系统中的某一服务。例如,MicroSoft Passport(Passport)服务使得开发人员能够对应用程序进行认证。通过对Passport服务编程,开发人员可以充分利用Passport的基本结构,通过运行Passport来维护用户数据库,以确保其正常运行、定期备份等等。 .NET正是根据这种Web服务原则而创建的,微软目前正着手提供这个基本结构,以便通过.NET平台的每一部分来实现这种新型的Web服务。而Visual Studio.NET、.NET框架、Windows.NET和.NET企业服务器,正是为进行基于Web服务模型的应用程序开发而度身定做的新一代开发工具和基本结构。.NET构建块服务、新增的.NET设备支持以及即将到来的.NET用户体验,将为人们彻底攻克这一难题划上一个圆满的句号,使人们能够充分利用Web服务模型,如愿以偿地开发出新一代应用程序。 l.NET对IT专业人员的重要意义 目前,IT专业人员能够利用与构建.NET平台相同的技术。 .NET Enterprise Servers和Windows 2000操作系统,为创建具有高度可管理性的、能迅速投入市场的应用程序提供了坚实基础。它们利用的是可扩展标记语言(XML),因此随着Web体系结构的革新,在此平台上创建的程序依然很有价值。 .NET平台的核心是,采用有效的、分门别类的方式来构建应用程序,达到其前所未有的规模。该平台上的Web服务模型指的是:企业应用程序的中心业务要素通常由本地管理,而支持它们的服务(如用户认证、文件存储、用户首选项管理、日历、邮件等等)却无须本地管理,可以被无缝订购。为了存储用户文件和邮件,IT专业人员往往在服务器上安装新的独立磁盘冗余阵列(RAID阵列),而有了.NET,他们在这一方面将会花费较少的精力,而更多地致力于怎样为公司增加效益。 该Web服务模型还将动态配置新软件的发布和更新。用户将以极其紧密的连接方式工作,因此更易于管理。而简化的管理又可使IT专业人员更能适应变幻莫测的业务需求。 开发应用程序的.NET Web服务模型将为企业应用程序的创建开辟一条新路。通过企业内外多种服务的联合,很容易把企业内部数据和客户及合作伙伴的相关数据结合在一起,大大简化了应用程序的创建过程。这就为最终用户发掘了空前的功能涵盖性。例如,利用某公司的雇员福利程序,可以从其HR数据库订购信息,通过Web订购福利管理公司的服务、订购工资管理公司的服务。终端用户可以在简单、直观的界面下操作,而这个界面可以显示他们的累积休假时间、个人所得福利以及上次工资额。 l.NET对企业的重要意义 MicroSoft .NET平台将从根本上改善计算机和用户之间进行交互的方式,最大限度地发挥电子商务中计算技术的重要作用。首先,让我们来分析一下当前商务计算世界的现状: 人与计算机进行交互的手段极为有限——通常使用键盘和鼠标进行输入,使用监视器监控输出。 用户信息基本上是本地信息;如果从另一台机器进行登录,则无法获取用户的个人首选项设置、数据及应用程序。 用户必须亲自处理信息,而通过设置智能选项代表用户自动进行操作,则无异于是纸上谈兵。 同一用户存放于不同应用程序和站点的数据,很难(或根本不可能)进行自动合并和关联,用户无法统一进行查看。 想在家里或在路上工作的用户,不能方便地访问办公室电脑中的应用程序和数据。这无疑成为一道阻止人们获得更高工作效率的鸿沟。 不能使用其它设备访问专为特定设备设计的数据(这些设备包括PC、寻呼机、移动电话以及PDA等);最多可以定期进行同步。 .NET将保证完全消除当今计算技术中的所有缺陷。.NET定能实现确保用户从任何地点、任何设备都可访问其个人数据和应用程序的宏伟蓝图。除此之外,.NET技术还可实现多个应用程序在逻辑上的松散耦合链接和紧密耦合链接。 用户可以通过手写、语音和图象技术与其个人数据进行交互。这些数据将安全地存放在互联网上,用户通过办公室(或家庭)PC,还可以通过移动电话或寻呼机、PDA、甚至是新发明的寻呼机——移动电话——PDA——PC联合设备访问这些数据。应用程序可进行灵活的功能调整,以适应用户所用设备的功能状况。应用程序可根据用户预定义的选项集和指令集,完全代替用户自动执行相应的操作。 |
|
|