站源碼解析:從用戶控件到數(shù)據(jù)綁定)
簡介基于ASP.NET的遼寧旅游網(wǎng)站畢業(yè)設(shè)計完整工程包面向計算機(jī)相關(guān)專業(yè)畢業(yè)生和希望掌握ASP.NET Web開發(fā)的初學(xué)者可用來完成畢業(yè)設(shè)計或作為實戰(zhàn)項目參考。項目覆蓋遼寧景點展示、信息瀏覽、留言反饋、訂單管理等典型功能涉及Web Forms、數(shù)據(jù)綁定、狀態(tài)管理、ADO.NET等知識便于系統(tǒng)學(xué)習(xí)。資源共111個文件主要包括12個aspx頁面、15個cs后臺邏輯文件、11個css樣式文件以及jpg/gif圖片素材、數(shù)據(jù)庫mdf/ldf文件和說明文檔壓縮包大小約4.04MB。已有176人學(xué)習(xí)下載。通過源碼可以梳理前臺頁面、后臺處理和數(shù)據(jù)訪問的分層結(jié)構(gòu)也可借助數(shù)據(jù)庫腳本和配置文件還原開發(fā)環(huán)境對于想理解ASP.NET項目完整組織方式或需要搭建旅游類網(wǎng)站的同學(xué)具有直接參考價值。1. 基于 ASP.NET 的遼寧旅游網(wǎng)站源碼先看清這套 Web Forms 工程再動手拿到這套基于 ASP.NET 的遼寧旅游網(wǎng)站畢業(yè)設(shè)計實現(xiàn)源碼時很多人第一反應(yīng)是打開 Reg.aspx 找登錄注冊代碼卻忽略了整套工程真正的主干其實是 header.ascx 這個用戶控件。rar 里包含的 10 個 aspx/ascx 文件覆蓋了游客注冊、景點查看、旅游線路查詢、新聞閱讀、意見反饋和我的訂單等模塊是一個標(biāo)準(zhǔn)的 ASP.NET Web Forms 表單驅(qū)動項目。它適合兩類人一類是用它做課程設(shè)計或畢業(yè)設(shè)計答辯的在校生另一類是想快速看懂老 ASP.NET 站點里頁面生命周期、數(shù)據(jù)綁定和狀態(tài)管理之間如何配合的開發(fā)者。項目本身沒有復(fù)雜的前端工程重點全部集中在服務(wù)端事件和 ADO.NET 數(shù)據(jù)訪問上按頁面逐個拆解反而更容易理解。2. 從 10 個文件名反推模塊header.ascx 與 aspx 頁面的協(xié)作結(jié)構(gòu)2.1 根據(jù)頁面命名還原業(yè)務(wù)清單這套源碼沒有打包完整的 PDF 設(shè)計文檔所以第一步應(yīng)該先從文件名確認(rèn)站點功能。下面這份對照關(guān)系是我基于文件名和 ASP.NET 畢業(yè)設(shè)計常見套路反推的可以幫你快速定位要改的頁面。文件名對應(yīng)業(yè)務(wù)核心技術(shù)點header.ascx全站頁頭Logo 與登錄菜單UserControl、Session 判斷Reg.aspx用戶注冊驗證控件、插入數(shù)據(jù)庫、寫入會話Help.aspx幫助中心靜態(tài)內(nèi)容頁引入 ascxSPLook.aspx景點查看Repeater/GridView 數(shù)據(jù)綁定YJFK.aspx意見反饋FormView 插入、回發(fā)校驗Update.aspx用戶資料更新參數(shù)化 Update 語句LXWM.aspx聯(lián)系我們靜態(tài)信息展示MyDDList.aspx我的訂單列表GridView 按用戶過濾查詢LXSLook.aspx旅游線路查看景點線路列表與詳情跳轉(zhuǎn)XWSee.aspx新聞查看QueryString 接收新聞 ID從命名習(xí)慣看這套工程的公共部分沒有用 MasterPage.master而是用 header.ascx 用戶控件承擔(dān)頁頭復(fù)用。這種寫法在老項目中很流行尤其是 2008 到 2013 年之間的畢業(yè)設(shè)計源碼因為用戶控件比母版頁更容易在多個獨立頁面里單獨控制登錄狀態(tài)。2.2 為什么選 ASP.NET Web Forms 而不是 MVC現(xiàn)在很多人在檢索 asp.net core 或 asp.net mvc 工作原理但這套源碼確定是 ASP.NET Web Forms。Web Forms 的事件驅(qū)動模型對畢業(yè)設(shè)計更有利每個 aspx 頁面都有自己的 Page_Load、Button_Click、GridView_RowCommand答辯時很容易按事件流程講業(yè)務(wù)邏輯。MVC 需要額外理解路由、Controller 與 Model 綁定反而把注冊下單這些簡單的流程拆散到多個層里。所以如果你拿到的題目是“基于 ASP.NET 的旅游網(wǎng)站”優(yōu)先保留 Web Forms 結(jié)構(gòu)比強(qiáng)行遷移成 MVC 更穩(wěn)妥。Web Forms 頁面生命周期中事件處理天然和頁面控件狀態(tài)綁定在一起代碼量少也更容易向評委展示數(shù)據(jù)如何從界面進(jìn)入數(shù)據(jù)庫。2.3 用戶控件 header.ascx 的注冊路徑寫法在 aspx 頁面中引用 header.ascx標(biāo)準(zhǔn)寫法是這樣的% Register Src~/header.ascx TagNameHeader TagPrefixuc % html headtitle遼寧旅游/title/head body uc:Header IDHeader1 runatserver / form idform1 runatserver div !-- 頁面主體內(nèi)容 -- /div /form /body /htmlSrc~/header.ascx中的~很重要它表示從站點根目錄開始解析路徑。如果寫成../header.ascx當(dāng)頁面在子目錄里時路徑會失效這是老 ASP.NET 部署時最常見的 500 錯誤來源。TagPrefixuc是自定義前綴頁面里用uc:Header標(biāo)簽引用這個控件ID 隨意但不能與現(xiàn)存控件沖突。2.4 Header 控件里的登錄狀態(tài)聯(lián)動header.ascx 的常見邏輯是在 Page_Load 里檢查 Sessionprotected void Page_Load(object sender, EventArgs e) { if (Session[username] ! null) { lbtnLogin.Visible false; lblUser.Text 歡迎 Session[username].ToString().Trim(); lbtnLogout.Visible true; } else { lbtnLogin.Visible true; lbtnLogout.Visible false; } }這里先判斷Session[username]是否為 null再做類型轉(zhuǎn)換避免 Session 過期后拋空引用異常。把這段邏輯放在 ascx 里所有引入 header 的頁面都能共享同一套登錄狀態(tài)渲染不需要每個 aspx 重復(fù)寫一遍。3. 頁面生命周期與注冊頁面實戰(zhàn)從 Reg.aspx 到 YJFK.aspx 的事件驅(qū)動3.1 Page_Load 與 IsPostBack 的執(zhí)行順序Web Forms 頁面每次請求都會經(jīng)歷 Init、Load、事件處理、PreRender、Render。大多數(shù)第一次寫這套源碼的人都踩過同一個坑在 Page_Load 里無條件綁定數(shù)據(jù)結(jié)果按鈕事件修改完數(shù)據(jù)庫后頁面又拿舊數(shù)據(jù)重新綁定看起來就是“改了沒生效”。正確做法是在首次加載時綁定初始數(shù)據(jù)回發(fā)時不重綁或重新判斷protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { BindCityDropDown(); BindSpotList(); } } protected void btnQuery_Click(object sender, EventArgs e) { BindSpotList(); }IsPostBack為 false 表示頁面第一次請求為 true 表示頁面通過表單回發(fā)。在回發(fā)時跳過初始綁定讓按鈕事件里的更新結(jié)果能直接反映到控件上。如果按鈕事件里要先讀取舊狀態(tài)可以在 Page_Load 中保留綁定代碼再用Page.IsPostBack分支控制。3.2 Reg.aspx 的驗證控件組合注冊頁常用的服務(wù)器控件結(jié)構(gòu)asp:TextBox IDtxtUserName runatserver/asp:TextBox asp:RequiredFieldValidator IDrfvUser runatserver ControlToValidatetxtUserName ErrorMessage用戶名不能為空 ForeColorRed / asp:TextBox IDtxtEmail runatserver/asp:TextBox asp:RegularExpressionValidator IDrevEmail runatserver ControlToValidatetxtEmail ValidationExpression^\w([-.]\w)*\w([-.]\w)*\.\w([-.]\w)*$ ErrorMessage郵箱格式不正確 / asp:Button IDbtnRegister runatserver Text注冊 OnClickbtnRegister_Click /驗證控件列表及其適用場景控件名作用適用場景RequiredFieldValidator必填項校驗用戶名、密碼不能為空RegularExpressionValidator正則匹配郵箱、手機(jī)號格式CompareValidator兩次輸入比較確認(rèn)密碼CustomValidator自定義服務(wù)端校驗用戶名是否已存在ValidationSummary匯總錯誤信息頁面頂部統(tǒng)一展示校驗不能只靠瀏覽器端 JS服務(wù)端在按鈕事件里還要檢查一次protected void btnRegister_Click(object sender, EventArgs e) { if (!Page.IsValid) { return; } string username txtUserName.Text.Trim(); string email txtEmail.Text.Trim(); int result UserDAO.Insert(username, txtPassword.Text, email); if (result 0) { Session[username] username; Response.Redirect(MyDDList.aspx); } else { lblMsg.Text 用戶名已存在或注冊失敗; } }Page.IsValid必須放在所有驗證控件執(zhí)行之后它匯總了服務(wù)端驗證結(jié)果。txtUserName.Text.Trim()是為了去掉用戶誤輸入的空格但不要在 Trim 后再賦值回控件否則回發(fā)時用戶看到的內(nèi)容會被改變。3.3 YJFK.aspx 的 FormView 插入模式意見反饋頁面最適合用 FormView 的默認(rèn)插入模式asp:FormView IDfvFeedback runatserver DataKeyNamesfeedbackid DefaultModeInsert OnItemInsertingfvFeedback_ItemInserting OnItemInsertedfvFeedback_ItemInserted InsertItemTemplate 標(biāo)題asp:TextBox IDtxtTitle runatserver / 內(nèi)容asp:TextBox IDtxtContent runatserver TextModeMultiLine Rows5 / asp:Button IDbtnSubmit runatserver CommandNameInsert Text提交反饋 / /InsertItemTemplate /asp:FormView后臺在插入前把會話信息補(bǔ)進(jìn)字段protected void fvFeedback_ItemInserting(object sender, FormViewInsertEventArgs e) { e.Values[username] Session[username] ?? 游客; e.Values[createtime] DateTime.Now; }CommandNameInsert是 FormView 內(nèi)置插入命令它會觸發(fā)ItemInserting事件。在事件里用e.Values賦值而不是改 InsertItemTemplate 里的 TextBox這樣避免了字段遺漏也讓數(shù)據(jù)庫的 createdate 默認(rèn)值可以統(tǒng)一設(shè)置。4. 數(shù)據(jù)綁定與 ADO.NETSPLook.aspx、LXSLook.aspx、MyDDList.aspx 的查詢與訂單操作4.1 Web.config 連接字符串配置數(shù)據(jù)訪問第一步是配置連接字符串connectionStrings add nameLiaoningTravelDB connectionStringData Source.;Initial CatalogTravelDB;User IDsa;Password123456; providerNameSystem.Data.SqlClient / /connectionStrings演示環(huán)境建議改成 Windows 集成認(rèn)證connectionStrings add nameLiaoningTravelDB connectionStringData Source.;Initial CatalogTravelDB;Integrated SecurityTrue; providerNameSystem.Data.SqlClient / /connectionStringsData Source.表示本機(jī) SQL ServerInitial Catalog是數(shù)據(jù)庫名。如果換成集成認(rèn)證不需要在代碼里暴露數(shù)據(jù)庫密碼也避免了 SQL Server 賬號密碼過期的問題。連接字符串變化時不需要重新編譯頁面只發(fā)布 Web.config 即可。4.2 公共數(shù)據(jù)訪問類 DbHelper把查詢邏輯封裝到 App_Code/DbHelper.cs是所有頁面引用的基礎(chǔ)public static class DbHelper { private static string connStr ConfigurationManager.ConnectionStrings[LiaoningTravelDB].ConnectionString; public static DataTable Query(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(connStr)) { using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null) { cmd.Parameters.AddRange(parameters); } SqlDataAdapter da new SqlDataAdapter(cmd); DataTable dt new DataTable(); da.Fill(dt); return dt; } } } public static int Execute(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(connStr)) { using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null) { cmd.Parameters.AddRange(parameters); } conn.Open(); return cmd.ExecuteNonQuery(); } } } }SqlDataAdapter.Fill()內(nèi)部會自動打開連接不需要手動Open()而ExecuteNonQuery()需要顯式打開連接。參數(shù)數(shù)組用params關(guān)鍵字可以讓調(diào)用方直接寫多個參數(shù)。每個方法都包在using里確保連接釋放避免并發(fā)訪問時連接池耗盡。4.3 SPLook.aspx 景點列表綁定 Repeater景點列表用 Repeater 比 GridView 更適合自由排版asp:Repeater IDrpSpot runatserver ItemTemplate h3%# Eval(spotname) %/h3 p%# Eval(spotdesc) %/p a hrefXWSee.aspx?id%# Eval(spotid) %查看詳情/a /ItemTemplate /asp:Repeater后臺protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { string city Request.QueryString[city]; if (string.IsNullOrEmpty(city)) { city 沈陽; } DataTable dt DbHelper.Query( SELECT spotid, spotname, spotdesc FROM spot WHERE citycity, new SqlParameter(city, city)); rpSpot.DataSource dt; rpSpot.DataBind(); } }Eval(spotname)是單向數(shù)據(jù)綁定讀取當(dāng)前綁定行中對應(yīng)列的值。Request.QueryString[city]可能為 null所以在拼 SQL 前給默認(rèn)值。這里用了參數(shù)化查詢避免把 city 直接拼進(jìn) SQL 造成注入。4.4 用 GridView 處理 MyDDList.aspx 的訂單列表訂單列表需要在 RowCommand 中處理取消訂單操作asp:GridView IDgvOrder runatserver AutoGenerateColumnsFalse DataKeyNamesorderid OnRowCommandgvOrder_RowCommand Columns asp:BoundField DataFieldorderno HeaderText訂單號 / asp:BoundField DataFieldstatus HeaderText狀態(tài) / asp:TemplateField HeaderText操作 ItemTemplate asp:LinkButton IDlbtnCancel runatserver CommandNameCancelOrder CommandArgument%# Eval(orderid) % Text取消訂單 OnClientClickreturn confirm(確認(rèn)取消?) / /ItemTemplate /asp:TemplateField /Columns /asp:GridView后臺事件protected void gvOrder_RowCommand(object sender, GridViewCommandEventArgs e) { if (e.CommandName CancelOrder) { int orderid Convert.ToInt32(e.CommandArgument); string username Session[username].ToString(); DbHelper.Execute( UPDATE orders SET status已取消 WHERE orderidorderid AND usernameusername, new SqlParameter(orderid, orderid), new SqlParameter(username, username)); BindOrderList(); } }CommandName自定義為CancelOrder避開 GridView 內(nèi)置的Delete命令防止觸發(fā)默認(rèn)刪除行為。CommandArgument綁定訂單 ID在 RowCommand 中把它轉(zhuǎn)成 int。更新語句中帶上username條件保證一個用戶不能改別人的訂單這是數(shù)據(jù)權(quán)限校驗的基本寫法。GridView 與 Repeater 的選型對比場景推薦控件原因表格化數(shù)據(jù)需要分頁排序GridView自帶分頁、排序自由排版文章/景點卡片Repeater輸出完全可控插入編輯一條記錄FormView / DetailsView內(nèi)置插入編輯模式兩表嵌套展示Repeater外層嵌套 ItemTemplate 靈活4.5 用 LINQ 做訂單金額統(tǒng)計老項目里常見的數(shù)據(jù)統(tǒng)計是在 DataTable 中循環(huán)累加其實可以用 LINQ to DataSet 簡化DataTable orderDt DbHelper.Query( SELECT orderno, amount, status FROM orders WHERE usernameusername, new SqlParameter(username, Session[username].ToString())); decimal totalPaid orderDt.AsEnumerable() .Where(row row.Fieldstring(status) 已支付) .Sum(row row.Fielddecimal(amount));AsEnumerable()把 DataTable 轉(zhuǎn)成可查詢的序列Fieldstring指定列類型。注意如果amount是 decimal但數(shù)據(jù)庫是 floatFielddecimal會拋異常要先確認(rèn)數(shù)據(jù)庫字段類型。LINQ 方式比 foreach 循環(huán)更清晰但在數(shù)據(jù)量很小的畢業(yè)設(shè)計里性能差異可以忽略。5. 狀態(tài)管理、身份驗證與部署從 Update.aspx 到 IIS 上跑通畢業(yè)設(shè)計5.1 用 Session 控制 MyDDList.aspx 和 Update.aspx 的訪問權(quán)限訂單頁面和資料更新頁面必須在用戶登錄后才能打開最簡單的控制是在 Page_Load 最前面加校驗protected void Page_Load(object sender, EventArgs e) { if (Session[username] null) { Response.Redirect(Reg.aspx); return; } if (!IsPostBack) { BindOrderList(); } }Response.Redirect之后必須加return否則當(dāng)前頁面會繼續(xù)執(zhí)行后續(xù)代碼控件可能因為沒有綁定數(shù)據(jù)而報錯。Session 有時間限制默認(rèn) 20 分鐘過期如果答辯時長時間不動頁面再點擊按鈕會被這條邏輯踢回注冊頁需要重新登錄。5.2 Web.config 的 Forms 身份驗證配置不想在每個頁面手寫判斷可以啟用 Forms 認(rèn)證authentication modeForms forms loginUrlReg.aspx timeout30 defaultUrlSPLook.aspx / /authentication authorization deny users? / /authorizationdeny users?表示拒絕匿名用戶訪問全站但這樣 Reg.aspx 本身也會被攔截所以要用location單獨放行注冊頁、景點頁和新聞頁location pathReg.aspx system.web authorization allow users? / /authorization /system.web /location這個配置比較繁瑣而且authorization在 IIS 經(jīng)典模式和集成模式下的層級解析有差異。對于這套畢業(yè)設(shè)計源碼我更推薦在需要保護(hù)的后臺頁面里用 Session 校驗直觀且不容易配錯。5.3 部署到 IIS 前要檢查的細(xì)節(jié)檢查項處理方式應(yīng)用程序池版本對應(yīng)編譯時的 .NET Framework 版本不能混用header.ascx 路徑所有注冊指令都用~開頭避免子目錄部署失效App_Code 目錄發(fā)布時保留 App_Code或預(yù)編譯成 bin dll連接字符串?dāng)?shù)據(jù)庫服務(wù)器名改成 localhost確認(rèn) SQL Server 服務(wù)已啟動防火墻本機(jī)調(diào)試時需放行 SQL Server 端口默認(rèn) 1433頁面里如果要動態(tài)引用~路徑的 js 文件直接用src~/js/jquery.js會被當(dāng)成普通相對路徑不會解析站點根目錄script src% ResolveUrl(~/js/jquery.js) %/scriptResolveUrl是 ASP.NET 內(nèi)置方法它把~轉(zhuǎn)成當(dāng)前根路徑。部署到虛擬目錄時/js/jquery.js可能會丟失虛擬目錄名而ResolveUrl能自動帶上應(yīng)用路徑。用這個方法替換所有手工拼接的相對路徑后站點放到 IIS 根目錄或子目錄都不會丟樣式。本文還有配套的精品資源點擊獲取