最近才看到網上有一種對asp.net web form的誤解。也有很多討論,弄得微軟ScottGu也來澄清。asp.net mvc和web form是並行存在的兩種開發模式。許多人對web form的詬病很多,其中最主要的就是說viewstate,隨便一個web form頁面,其html源碼就體積很大,主要是隱藏欄位viewstate體積比較大,至少幾十K,頁面複雜一點,viewstate的大小能上幾兆,這樣大體積的頁面,在瀏覽器和伺服器之間傳輸,對網路頻寬也是一個很大的壓力,所以asp.net webform的效能肯定受很大影響。這其實是一個對asp.net web form的特大誤解。這裡提供一個小技巧。可以讓asp.net web form的頁面和asp.net mvc的頁面一樣體積小巧。同時還能享受viewstate帶來的好處。
舉例來說:一個顯示記錄列表的form。如:
這是一個很簡單的頁面了。其html原始碼是:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title> </title></head><body> <form method="post" action="Default.aspx" id="form1"><div class="aspNetHidden"><input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" /><input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" /><input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTE5MTIyNjE4Mg9kFgJmD2QWAgIDD2QWAgIBD2QWAgIDDzwrABECAA8WBB4LXyFEYXRhQm91bmRnHgtfIUl0ZW1Db3VudALCA2QMFCsABxYIHgROYW1lBQlBZGRyZXNzSUQeCklzUmVhZE9ubHloHgRUeXBlGSsBHglEYXRhRmllbGQFCUFkZHJlc3NJRBYIHwIFDEFkZHJlc3NMaW5lMR8DaB8EGSsCHwUFDEFkZHJlc3NMaW5lMRYIHwIFDEFkZHJlc3NMaW5lMh8DaB8EGSsCHwUFDEFkZHJlc3NMaW5lMhYIHwIFBENpdHkfA2gfBBkrAh8FBQRDaXR5FggfAgUNU3RhdGVQcm92aW5jZR8DaB8EGSsCHwUFDVN0YXRlUHJvdmluY2UWCB8CBQ1Db3VudHJ5UmVnaW9uHwNoHwQZKwIfBQUNQ291bnRyeVJlZ2lvbhYIHwIFClBvc3RhbENvZGUfA2gfBBkrAh8FBQpQb3N0YWxDb2RlFgJmD2QWDAIBD2QWDmYPDxYCHgRUZXh0BQE5ZGQCAQ8PFgIfBgURODcxMyBZb3NlbWl0ZSBDdC5kZAICDw8WAh8GBQYmbmJzcDtkZAIDDw8WAh8GBQdCb3RoZWxsZGQCBA8PFgIfBgUKV2FzaGluZ3RvbmRkAgUPDxYCHwYFDVVuaXRlZCBTdGF0ZXNkZAIGDw8WAh8GBQU5ODAxMWRkAgIPZBYOZg8PFgIfBgUCMTFkZAIBDw8WAh8GBRMxMzE4IExhc2FsbGUgU3RyZWV0ZGQCAg8PFgIfBgUGJm5ic3A7ZGQCAw8PFgIfBgUHQm90aGVsbGRkAgQPDxYCHwYFCldhc2hpbmd0b25kZAIFDw8WAh8GBQ1Vbml0ZWQgU3RhdGVzZGQCBg8PFgIfBgUFOTgwMTFkZAIDD2QWDmYPDxYCHwYFAjI1ZGQCAQ8PFgIfBgUQOTE3OCBKdW1waW5nIFN0LmRkAgIPDxYCHwYFBiZuYnNwO2RkAgMPDxYCHwYFBkRhbGxhc2RkAgQPDxYCHwYFBVRleGFzZGQCBQ8PFgIfBgUNVW5pdGVkIFN0YXRlc2RkAgYPDxYCHwYFBTc1MjAxZGQCBA9kFg5mDw8WAh8GBQIyOGRkAgEPDxYCHwYFEDkyMjggVmlhIERlbCBTb2xkZAICDw8WAh8GBQYmbmJzcDtkZAIDDw8WAh8GBQdQaG9lbml4ZGQCBA8PFgIfBgUHQXJpem9uYWRkAgUPDxYCHwYFDVVuaXRlZCBTdGF0ZXNkZAIGDw8WAh8GBQU4NTAwNGRkAgUPZBYOZg8PFgIfBgUCMzJkZAIBDw8WAh8GBREyNjkxMCBJbmRlbGEgUm9hZGRkAgIPDxYCHwYFBiZuYnNwO2RkAgMPDxYCHwYFCE1vbnRyZWFsZGQCBA8PFgIfBgUGUXVlYmVjZGQCBQ8PFgIfBgUGQ2FuYWRhZGQCBg8PFgIfBgUHSDFZIDJINWRkAgYPDxYCHgdWaXNpYmxlaGRkGAEFJGN0bDAwJENvbnRlbnRQbGFjZUhvbGRlcjEkZ3JkQWRkcmVzcw88KwAMAQgCWmTq1MHx+5oLH4bMzg2GUy0MyKZQYkR2RY+bxLLJQFR/nQ==" /></div> <script type="text/javascript"> //<![CDATA[var theForm = document.forms['form1'];if (!theForm) { theForm = document.form1;}function __doPostBack(eventTarget, eventArgument) { if (!theForm.onsubmit || (theForm.onsubmit() != false)) { theForm.__EVENTTARGET.value = eventTarget; theForm.__EVENTARGUMENT.value = eventArgument; theForm.submit(); }}//]]></script> <div> <span id="ContentPlaceHolder1_Label1">My label</span><div><table cellspacing="0" rules="all" border="1" id="ContentPlaceHolder1_grdAddress" style="border-collapse:collapse;"><tr><th scope="col">AddressID</th><th scope="col">AddressLine1</th><th scope="col">AddressLine2</th><th scope="col">City</th><th scope="col">StateProvince</th><th scope="col">CountryRegion</th><th scope="col">PostalCode</th></tr><tr><td>9</td><td>8713 Yosemite Ct.</td><td> </td><td>Bothell</td><td>Washington</td><td>United States</td><td>98011</td></tr><tr><td>11</td><td>1318 Lasalle Street</td><td> </td><td>Bothell</td><td>Washington</td><td>United States</td><td>98011</td></tr><tr><td>25</td><td>9178 Jumping St.</td><td> </td><td>Dallas</td><td>Texas</td><td>United States</td><td>75201</td></tr><tr><td>28</td><td>9228 Via Del Sol</td><td> </td><td>Phoenix</td><td>Arizona</td><td>United States</td><td>85004</td></tr><tr><td>32</td><td>26910 Indela Road</td><td> </td><td>Montreal</td><td>Quebec</td><td>Canada</td><td>H1Y 2H5</td></tr><tr><td colspan="7"><table><tr><td><span>1</span></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$2')">2</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$3')">3</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$4')">4</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$5')">5</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$6')">6</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$7')">7</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$8')">8</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$9')">9</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$10')">10</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$11')">...</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$Last')">>></a></td></tr></table></td></tr></table></div><br /> </div> </form></body></html>
可見其隱藏欄位viewstate體積較大。對應用程式的效能會有較大影響。
通過如下方法,可以讓頁面html原始碼體積變小巧。
using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace EntLibSample{ public class BasePage : System.Web.UI.Page { protected override void SavePageStateToPersistenceMedium(object viewState) { Session["viewState" + this.Context.Request.FilePath] = viewState; } protected override object LoadPageStateFromPersistenceMedium() { if (Session["viewState" + this.Context.Request.FilePath] != null) { return Session["viewState" + this.Context.Request.FilePath]; } return string.Empty; } }}
這個BasePage類繼承了System.Web.UI.Page類。System.Web.UI.Page中的SavePageStateToPersistenceMedium和LoadPageStateFromPersistenceMedium方法是將viewstate的內容發到用戶端瀏覽器中,那麼每次向伺服器發請求,都需將體積龐大的viewstate欄位發回伺服器,伺服器返回結果時,又將體積龐大的viewstate欄位發回來。這給應用程式整體效能帶來了很大衝擊。BasePage類改寫了此兩個方法。將viewstate內容放到session中,用的時候又從session取回來。這樣避免了在網路上來回傳輸體積龐大的viewstate內容。
應用程式的所有頁面都繼承此BasePage類。這樣就可以將此方法應用於所有的asp.net web form頁面。
其效果如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title> </title></head><body> <form method="post" action="Default.aspx" id="form1"><div class="aspNetHidden"><input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" /><input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" /><input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="" /></div> <script type="text/javascript"> //<![CDATA[var theForm = document.forms['form1'];if (!theForm) { theForm = document.form1;}function __doPostBack(eventTarget, eventArgument) { if (!theForm.onsubmit || (theForm.onsubmit() != false)) { theForm.__EVENTTARGET.value = eventTarget; theForm.__EVENTARGUMENT.value = eventArgument; theForm.submit(); }}//]]></script> <div> <span id="ContentPlaceHolder1_Label1">My label</span><div><table cellspacing="0" rules="all" border="1" id="ContentPlaceHolder1_grdAddress" style="border-collapse:collapse;"><tr><th scope="col">AddressID</th><th scope="col">AddressLine1</th><th scope="col">AddressLine2</th><th scope="col">City</th><th scope="col">StateProvince</th><th scope="col">CountryRegion</th><th scope="col">PostalCode</th></tr><tr><td>9</td><td>8713 Yosemite Ct.</td><td> </td><td>Bothell</td><td>Washington</td><td>United States</td><td>98011</td></tr><tr><td>11</td><td>1318 Lasalle Street</td><td> </td><td>Bothell</td><td>Washington</td><td>United States</td><td>98011</td></tr><tr><td>25</td><td>9178 Jumping St.</td><td> </td><td>Dallas</td><td>Texas</td><td>United States</td><td>75201</td></tr><tr><td>28</td><td>9228 Via Del Sol</td><td> </td><td>Phoenix</td><td>Arizona</td><td>United States</td><td>85004</td></tr><tr><td>32</td><td>26910 Indela Road</td><td> </td><td>Montreal</td><td>Quebec</td><td>Canada</td><td>H1Y 2H5</td></tr><tr><td colspan="7"><table><tr><td><span>1</span></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$2')">2</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$3')">3</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$4')">4</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$5')">5</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$6')">6</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$7')">7</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$8')">8</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$9')">9</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$10')">10</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$11')">...</a></td><td><a href="javascript:__doPostBack('ctl00$ContentPlaceHolder1$grdAddress','Page$Last')">>></a></td></tr></table></td></tr></table></div><br /> </div> </form></body></html>
可見viewstate欄位的內容完全沒有了。這樣html原始碼的整體體積就小了很多。這對應用程式的效能提高是很大好處的。曾經只有asp.net mvc才有的體積小頁面,現在asp.net web form也可以做到了。同時asp.net web form還有開發效率相對較高,還可以利用viewstate帶來的好處,有了這些綜合考慮,大家應該會重拾對asp.net web form的信心,繼續在asp.net web form的旅程。