自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ASP.NET數(shù)據(jù)綁定的內(nèi)部機(jī)理淺析

開(kāi)發(fā) 后端
這個(gè)簡(jiǎn)短的系列文章就是帶我們大家一起去深入探究一下ASP.NET綁定語(yǔ)法的內(nèi)部機(jī)理,以讓我們更加全面的認(rèn)識(shí)和運(yùn)用它。

在ASP.NET我們?cè)谑褂肦epeater,DetailsView,F(xiàn)ormView,GridView等數(shù)據(jù)綁定模板時(shí),都會(huì)使用< %# Eval("字段名") %>或< %# Bind("字段名") %>這樣的語(yǔ)法來(lái)單向或雙向綁定數(shù)據(jù)。但是我們卻很少去了解,在這些語(yǔ)法的背后,ASP.NET究竟都做了哪些事情來(lái)方便我們使用這樣的語(yǔ)法來(lái)綁定數(shù)據(jù)。究竟解析這樣的語(yǔ)法是在編譯時(shí),還是運(yùn)行時(shí)?如果沒(méi)有深入去了解,我們肯定不得而知。這個(gè)簡(jiǎn)短的系列文章就是帶我們大家一起去深入探究一下ASP.NET綁定語(yǔ)法的內(nèi)部機(jī)理,以讓我們更加全面的認(rèn)識(shí)和運(yùn)用它。

事件的起因是,我希望動(dòng)態(tài)的為Repeater控件添加行項(xiàng)模板,我可以通過(guò)實(shí)現(xiàn)ITempate接口的方式來(lái)動(dòng)態(tài)添加行模板。并希望它通過(guò)普通的頁(yè)面綁定語(yǔ)法來(lái)完成數(shù)據(jù)字段的綁定功能,如下就是一個(gè)簡(jiǎn)單的例子:

   1: /// < summary>
   2: /// Summary description for DynamicTemplate
   3: /// < /summary>
   4: public class DynamicTemplate : ITemplate
   5: {
   6:     public DynamicTemplate()
   7:     {
   8:         //
   9:         // TODO: Add constructor logic here
  10:         //
  11:     }
  12:     #region ITemplate Members
  13:  
  14:     public void InstantiateIn(Control container)
  15:     {
  16:         TextBox textBox = new TextBox();
  17:         textBox.Text = @"< %# Eval(""ID"") %>";
  18:         container.Controls.Add(textBox);
  19:     }
  20:     #endregion
  21: }

在這個(gè)例子中,我在模板中添加了一個(gè)TextBox控件,并指定它的綁定字段是“ID”。但是這做法,能否實(shí)現(xiàn)我們實(shí)現(xiàn)我們需要的功能呢?答案是否定,每一行的TextBox的值都是"< %# Eval(""ID"") %>",而不會(huì)像我們希望的那樣去綁定ID字段。從結(jié)果來(lái)分析原因,我們可以非常容易得出,這段綁定語(yǔ)法并沒(méi)有得到ASP.NET運(yùn)行時(shí)的承認(rèn),那么頁(yè)面中使用相同的語(yǔ)法為什么可以呢?故事就是從這里開(kāi)始的。

我們首先要去了解下,在頁(yè)面中使用這樣的語(yǔ)法ASP.NET都為我們做了哪些事情呢?要了解這個(gè),我們要找到.aspx文件在首次運(yùn)行時(shí)動(dòng)態(tài)編譯的程序集。

我們都知道,在ASP.NET運(yùn)行時(shí),也會(huì)把.aspx文件編譯成一個(gè)動(dòng)態(tài)類,這個(gè)類是繼承于.aspx的Page指令中Inherits屬性指定的類并且同時(shí)也直接實(shí)現(xiàn)了IHttpHandler接口。這個(gè)動(dòng)態(tài)類會(huì)負(fù)責(zé)創(chuàng)建頁(yè)面中使用的各種服務(wù)器端控件的實(shí)例,并且ASP.NET運(yùn)行時(shí)會(huì)負(fù)責(zé)解析的編譯.aspx中存在的服務(wù)器端代碼(包括綁定語(yǔ)法)并將這些代碼編譯到這個(gè)頁(yè)面類。WebSite工程和Web Application在頁(yè)面文件上有些不同,WebSite工程的每個(gè)頁(yè)面最多可以有兩個(gè)文件:.aspx和.aspx.cs文件;而在Web Application還可以包括.aspx.designer.cs文件,這個(gè)文件所起的作用也非常有限,也就是為了能在頁(yè)面代碼中使用服務(wù)器端、控件實(shí)例而定義的一個(gè)實(shí)例變量,僅此而已。所以在設(shè)計(jì)時(shí)WebSite具備更多的動(dòng)態(tài)行為,而在運(yùn)行時(shí)WebSite工程和Web Application并沒(méi)有太大區(qū)別。

如何得到頁(yè)面的動(dòng)態(tài)類呢?要首先得到這個(gè)頁(yè)所在的動(dòng)態(tài)程序集,在Vista以前的操作系統(tǒng)上,一般是在:%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 文件夾下,而在Vista中,而會(huì)在:%USERPROFILE%\AppData\Local\Temp\Temporary ASP.NET Files下。那么如何快速得到程序集的路徑和名稱?你可以讓你的Web工程動(dòng)態(tài)編譯出錯(cuò)(比如重復(fù)的類名),就可以快速定位到當(dāng)前動(dòng)態(tài)程序集的目錄了。

動(dòng)態(tài)類中會(huì)有很多的內(nèi)容,我們不作更多的分析,我們把目光集中綁定代碼上。假設(shè)現(xiàn)在頁(yè)面上有這么一段Repeater綁定代碼:

   1: < asp:Repeater runat="server" ID="repeater">
   2:     < HeaderTemplate>
   3:         < table>
   4:             < tr>
   5:                 < td>
   6:                     ID
   7:                 < /td>
   8:                 < td>
   9:                     電流{a}
  10:                 < /td>
  11:                  < td>電壓(V)< /td>
  12:                 < td>
  13:                     備注'
  14:                 < /td>
  15:                 < td>
  16:                     名稱]
  17:                 < /td>
  18:             < /tr>
  19:     < /HeaderTemplate>
  20:     < ItemTemplate>
  21:         < tr>
  22:             < td>
  23:                 < %# Eval("ID")%>
  24:             < /td>
  25:             < td>
  26:                 < %# Eval("電流{a}")%>
  27:             < /td>
  28:             < td>< %# Eval("電壓(V)")%>< /td>
  29:             < td>
  30:                 < %# Eval("備注'")%>
  31:             < /td>
  32:             < td>
  33:                 < %# Eval("名稱]")%>
  34:             < /td>
  35:         < /tr>
  36:     < /ItemTemplate>
  37:     < FooterTemplate>
  38:         < /table>
  39:     < /FooterTemplate>
  40: < /asp:Repeater>

那么在動(dòng)態(tài)類中,相應(yīng)的會(huì)有這樣的一段函數(shù),是用來(lái)創(chuàng)建ID為repeater的控件實(shí)例:

   1: [DebuggerNonUserCode]
   2: private Repeater __BuildControlrepeater()
   3: {
   4:     Repeater repeater = new Repeater();
   5:     base.repeater = repeater;
   6:     repeater.HeaderTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control4));
   7:     repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control5));
   8:     repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7));
   9:     repeater.ID = "repeater";
  10:     return repeater;
  11: }
  12:  
  13:  

CompiledTempateBuilder和BuildTemplateMethod只是模板實(shí)例化的一個(gè)中介,真正用于添加模板內(nèi)容的是后面的那些私有函數(shù),如ItemTempate的模板內(nèi)容實(shí)例的創(chuàng)建就在__BuildControl__control5函數(shù)中,這個(gè)函數(shù)原型定義是:

   1: [DebuggerNonUserCode]
   2: private void __BuildControl__control5(Control __ctrl)
   3: {
   4:     DataBoundLiteralControl control = this.__BuildControl__control6();
   5:     IParserAccessor accessor = __ctrl;
   6:     accessor.AddParsedSubObject(control);
   7: }
   8:  

在這個(gè)函數(shù)里,調(diào)用了另一個(gè)私有函數(shù)this.__BuildControl__control6,這個(gè)函數(shù)返回的一個(gè)DataBoundLiteralControl對(duì)象,并將對(duì)象輸出添加到__ctrl參數(shù)。事實(shí)上,只要我們?nèi)ラ喿xCompiledTempateBuilder就發(fā)現(xiàn)在,這里的__ctrol對(duì)象就是我們?cè)趯?shí)例化模板時(shí)傳入的對(duì)象,也就是ITemplate中的InstantiateIn方法的那個(gè)container參數(shù)對(duì)象。

為什么使用的是AddParsedSubObject方法,使用這個(gè)方法添加子控件相當(dāng)于告訴父控件,這是一個(gè)已經(jīng)解析好的子控件對(duì)象,不需再去將控件解析成HTML代碼,而在輸出時(shí)直接輸出Text屬性的值即可。從這里我們還可以得知DataBoundLiteralControl的對(duì)象,事實(shí)上就是承擔(dān)了字符串拼接的職責(zé),這一點(diǎn)我們可以在后面的分析中得以驗(yàn)證。

__BuildControl__control6私有函數(shù)的定義如下:

   1: [DebuggerNonUserCode]
   2: private DataBoundLiteralControl __BuildControl__control6()
   3: {
   4:     DataBoundLiteralControl control = new DataBoundLiteralControl(5, 4);
   5:     control.TemplateControl = this;
   6:     control.SetStaticString(0, "\r\n                < tr>\r\n                    < td>\r\n                        ");
   7:     control.SetStaticString(1, "\r\n                    < /td>\r\n                    < td>\r\n                        ");
   8:     control.SetStaticString(2, "\r\n                    < /td>\r\n                    \r\n                    < td>\r\n                        ");
   9:     control.SetStaticString(3, "\r\n                    < /td>\r\n                    < td>\r\n                        ");
  10:     control.SetStaticString(4, "\r\n                    < /td>\r\n                < /tr>\r\n            ");
  11:     control.DataBinding += new EventHandler(this.__DataBind__control6);
  12:     return control;
  13: }

在這個(gè)函數(shù)里面,創(chuàng)建了一個(gè)DataBoundLiteralControl對(duì)象,并將頁(yè)面上定義的模板的靜態(tài)HTML代碼添加到該的靜態(tài)字符串?dāng)?shù)組里,并且設(shè)置了它的綁定事件代理函數(shù)__DataBind__control6,該函數(shù)的定義:

   1: public void __DataBind__control6(object sender, EventArgs e)
   2: {
   3:     DataBoundLiteralControl control = (DataBoundLiteralControl) sender;
   4:     RepeaterItem bindingContainer = (RepeaterItem) control.BindingContainer;
   5:     control.SetDataBoundString(0, Convert.ToString(base.Eval("ID"), CultureInfo.CurrentCulture));
   6:     control.SetDataBoundString(1, Convert.ToString(base.Eval("電流{a}"), CultureInfo.CurrentCulture));
   7:     control.SetDataBoundString(2, Convert.ToString(base.Eval("備注'"), CultureInfo.CurrentCulture));
   8:     control.SetDataBoundString(3, Convert.ToString(base.Eval("名稱]"), CultureInfo.CurrentCulture));
   9: }

在這個(gè)函數(shù)中,我們看到了真正的數(shù)據(jù)綁定代碼了,它調(diào)用了TemplateControl的Eval方法來(lái)將當(dāng)前數(shù)據(jù)項(xiàng)的相應(yīng)字段的值取出,并按一定的格式轉(zhuǎn)化后添加到DataBoundLitreralControl對(duì)象中,并在DataBoundLiteralControl將StaticString和DataBoundString字符串?dāng)?shù)組按一定的順序拼接起來(lái),作為Text屬性的輸出值。而容器控件則直接向客戶端輸這段HTML。

下面,我們還有必要來(lái)分析下TemplateControl中的Eval方法,這個(gè)方法有兩種重載,簡(jiǎn)單起見(jiàn),我們來(lái)分析較為簡(jiǎn)單的重載:

   1: protected internal object Eval(string expression)
   2: {
   3:     this.CheckPageExists();
   4:     return DataBinder.Eval(this.Page.GetDataItem(), expression);
   5: }

這個(gè)方法,使用了DataBinder.Eval靜態(tài)方法來(lái)得到綁定表達(dá)式(字段名)的值,它的數(shù)據(jù)是通過(guò)this.Page.GetDataItem()這樣的一個(gè)方法得到的。那么為什么this.Page.GetDataItem()就可以得到當(dāng)前正在被綁定的數(shù)據(jù)項(xiàng)呢?原來(lái),在頁(yè)面綁定數(shù)據(jù)時(shí),它會(huì)有一個(gè)堆棧來(lái)保存它所有的綁定控件綁定時(shí)用到的數(shù)據(jù)項(xiàng),我們只需要取得堆棧頂部的那個(gè)元素,就可以在頁(yè)面的作用域內(nèi)的任何一個(gè)位置得到當(dāng)前正在被綁定的數(shù)據(jù)項(xiàng)。如上的例子,我們就可以取得當(dāng)前綁定的RepeaterItem的DataItem的數(shù)據(jù)項(xiàng),因此我們不需要與RepeaterItem有任何的聯(lián)系。

如果硬要用上面的代碼來(lái)描述數(shù)據(jù)綁定的全過(guò)程,跨度過(guò)大。但是有了以上的分析,我們?cè)儆梦淖值男问皆賮?lái)總結(jié)下,應(yīng)該就會(huì)一個(gè)比較完整的印象了:在ASP.NET的數(shù)據(jù)模板控件中,可以使用< %# %>這樣的語(yǔ)法來(lái)將字段值作為一個(gè)占位符,用在HTML代碼中,可以方便我們?cè)O(shè)計(jì)和生成最終的HTML代碼,不需要很多的字符拼接工作。而ASP.NET運(yùn)行時(shí)在首次執(zhí)行頁(yè)面時(shí),會(huì)為頁(yè)面編譯一個(gè)動(dòng)態(tài)類,在這個(gè)動(dòng)態(tài)類中會(huì)實(shí)例化所有的服務(wù)器端控件,編譯和解析綁據(jù)模板控件的綁定語(yǔ)法,并用一些對(duì)象和操作來(lái)完成數(shù)據(jù)綁定的字符串接拼接行為。因此綁定語(yǔ)法的解析事實(shí)上是編譯時(shí)的行為,只不過(guò)這個(gè)編譯時(shí)是延遲到頁(yè)面的首次執(zhí)行時(shí)。這就可以解釋為什么在我們想在動(dòng)態(tài)添加模板中使用< %# %>這樣的綁定語(yǔ)法時(shí),無(wú)法解析的原因。

而對(duì)于DataBinder.Eval方法,這是ASP.NET提供的一個(gè)數(shù)據(jù)綁定輔助方法。通過(guò)這個(gè)方法,我們可以方便的從種不同的數(shù)據(jù)項(xiàng),如自定義對(duì)象或DataRow取出對(duì)象的字段(屬性值)。從而為我們屏蔽很多不必要的數(shù)據(jù)來(lái)源類型的判斷。同時(shí)DataBinder這個(gè)類還提供了其它的綁定輔助方法,大家可以從MSDN查看更多有用的有關(guān)ASP.NET數(shù)據(jù)綁定的幫助。

【編輯推薦】

  1. 介紹一些ASP.NET工作流學(xué)習(xí)資料
  2. 調(diào)用ASP.NET工作流:承載及限制
  3. ASP.NET工作流的創(chuàng)建與啟動(dòng)
  4. ASP.NET數(shù)據(jù)庫(kù)連接類ClassConn以及oledb數(shù)據(jù)庫(kù)連接方法
  5. ASP.NET數(shù)據(jù)庫(kù)驅(qū)動(dòng)類的實(shí)現(xiàn):DBHelper
責(zé)任編輯:yangsai 來(lái)源: 博客園
相關(guān)推薦

2009-08-07 15:34:15

ASP.NET數(shù)據(jù)綁定

2009-08-03 18:15:05

ASP.NET數(shù)據(jù)綁定

2009-08-04 10:02:36

中國(guó)站長(zhǎng)站

2009-07-27 15:34:11

MembershipASP.NET

2009-07-27 10:18:12

TypeResolveASP.NET

2009-07-22 17:21:27

ASP.NET 2.0

2009-07-28 14:06:28

ASP.NET 2.0

2009-08-03 18:35:51

ASP.NET數(shù)據(jù)緩存

2009-07-24 13:41:15

ASP.NET AJA

2009-08-05 18:36:12

ASP.NET Che

2009-07-31 12:43:59

ASP.NET MVC

2009-08-05 15:50:13

ASP.NET優(yōu)點(diǎn)

2009-07-22 18:03:00

ASP.NET ASP

2009-08-10 13:32:15

ASP.NET TimASP.NET組件設(shè)計(jì)

2009-08-05 17:26:25

ASP.NET 2.0

2009-07-29 14:12:45

ASP.NET tra

2009-07-28 17:36:21

ASP.NET數(shù)據(jù)庫(kù)連

2009-08-04 14:56:34

ASP.NET數(shù)據(jù)類型

2009-07-31 09:57:47

ASP.NET數(shù)據(jù)庫(kù)緩

2009-08-04 15:20:59

ASP.NET數(shù)據(jù)驗(yàn)證數(shù)據(jù)驗(yàn)證控件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)