用多層架構構建一個簡易留言本
發表時間:2023-08-18 來源:明輝站整理相關軟件相關文章人氣:
[摘要]kaneboy@163.net ASP.NET終于可以讓Web開發人員從ASP的面條代碼中脫身出來,以全新的方式來構建Web站點,就像Windows Application一樣,我們...
kaneboy@163.net
ASP.NET終于可以讓Web開發人員從ASP的面條代碼中脫身出來,以全新的方式來構建Web站點,就像Windows Application一樣,我們同樣可以用面向對象的、多層的方式來組織和構建Web Application。
下面給出的是一個功能非常簡單的留言本程序,旨在揭示ASP.NET強大的能力和全新的開發方式。如果只相對留言本程序本身而言,大家可能懷疑用這么多的氣力實現如此簡單的程序是否值得,但我說過,例子只是用來說明問題和描述解決方案。其實我認為,從維護和擴充的角度來說,即使再簡單的程序,從一開始就進行良好的設計也是非常值得的。
留言本采用多層的方式來構建,下面的介紹為了方便大家理解,并未按照層次的順序介紹:
一、數據實體(CMessageData類)
CMessageData派生自DataSet,用來維護留言數據,在構造函數中,調用CreateDataTables()來增加一個用來保存留言數據的DataTable,并加到自身的DataTable集合中。靜態屬性TableMapping用來描述這個DataTable的DataColumn和數據庫中物理字段的映射關系,數據訪問層將使用這個屬性來填充數據進CMessageData對象中。
public class CMessageData : DataSet {
public CMessageData() {
this.CreateDataTables();
}
public static DataTableMapping TableMapping {
get {
DataTableMapping result = new DataTableMapping("t_gbook_postinfo", "MessageTable");
result.ColumnMappings.Add("id", "Id");
result.ColumnMappings.Add("last_reply_time", "LastReplyTime");
//…..
return result;
}
}
private void CreateDataTables() {
DataTable dt = new DataTable("MessageTable");
dt.Columns.Add("Id", typeof(Int32));
dt.Columns.Add("LastReplyTime", typeof(DateTime));
// …..
dt.Columns["Id"].AutoIncrement = true;
dt.Columns["Id"].AutoIncrementSeed = 0;
dt.Columns["Id"].AutoIncrementStep = -1;
dt.PrimaryKey = new DataColumn[] {dt.Columns["Id"]};
this.Tables.Add(dt);
}
AddedNewRow屬性返回一個新增進數據表的、空的DataRow,用于給邏輯層填充。FillDataFormDataBase()的兩個重載調用數據訪問層的相應方法來填充一個新的CMessageData對象并返回。UpdateToDatabase用于講自身的數據更改更新回數據庫。
public DataRow AddedNewRow()…
public static CMessageData FillDataFromDatabase(Int32 startRecord, Int32 maxRecord)…
public static CMessageData FillDataFromDatabase(Int32 id)…
public void UpdateToDatabase()…
二、數據訪問層(CDataAccess類)
負責連接數據庫,進行SIUD(Select,Insert,Update,Delete)操作。數據連接信息放在AppParameters.xml文件中。
FillMessageData()的兩個重載創建新的CMessageData對象,填充數據,然后返回:
public static CMessageData FillMessageData(Int32 startRecord, Int32 maxRecord)
public static CMessageData FillMessageData(Int32 id)
UpdateMessageData()把參數中的CMessageData對象所作出的更改更新回數據庫:
public static Int32 UpdateMessageData(CMessageData messageData) {
OleDbConnection conn = new OleDbConnection(CAppParameters.OleDbConnectionString);
OleDbCommand cmdSelect = new OleDbCommand("Select username,last_reply_time,guest_name,guest_email,guest_website_name,guest_website_url,guest_oicq,guest_ip,guest_post_time,guest_text,reply_data From t_gbook_postinfo", conn);
OleDbCommand cmdInsert = new OleDbCommand();
cmdInsert.Connection = conn;
cmdInsert.CommandText = "Insert Into t_gbook_postinfo (last_reply_time,guest_name,guest_email,guest_website_name,guest_website_url,guest_oicq,guest_ip,guest_post_time,guest_text,reply_data) Values (@last_reply_time,@guest_name,@guest_email,@guest_website_name,@guest_website_url,@guest_oicq,@guest_ip,@guest_post_time,@guest_text,@reply_data)";
cmdInsert.Parameters.Add("@last_reply_time", OleDbType.DBDate, 0, "last_reply_time");
cmdInsert.Parameters.Add("@guest_name", OleDbType.VarWChar, 255, "guest_name");
//…
OleDbCommand cmdUpdate = new OleDbCommand();
cmdUpdate.Connection = conn;
cmdUpdate.CommandText = "Update t_gbook_postinfo Set last_reply_time=@last_reply_time,guest_name=@guest_name,guest_email=@guest_email,guest_website_name=@guest_website_name,guest_website_url=@guest_website_url,guest_oicq=@guest_oicq,guest_ip=@guest_ip,guest_post_time=@guest_post_time,guest_text=@guest_text,reply_data=@reply_data Where (id=@Original_id)";
cmdUpdate.Parameters.Add("@last_reply_time", OleDbType.DBDate, 0, "last_reply_time");
cmdUpdate.Parameters.Add("@guest_name", OleDbType.VarWChar, 255, "guest_name");
//…
OleDbCommand cmdDelete = new OleDbCommand();
cmdDelete.Connection = conn;
cmdDelete.CommandText = @"Delete From t_gbook_postinfo where (id = @Original_id)";
cmdDelete.Parameters.Add("@Original_id", OleDbType.Integer, 0, "id").SourceVersion = DataRowVersion.Original;
OleDbDataAdapter ada = new OleDbDataAdapter(cmdSelect);
ada.InsertCommand = cmdInsert;
ada.UpdateCommand = cmdUpdate;
ada.DeleteCommand = cmdDelete;
ada.TableMappings.Add(CMessageData.TableMapping);
return ada.Update(messageData, "t_gbook_postinfo");
}
把數據訪問層單獨提取出來的好處就是其他層都不會直接和數據庫打交道,如果我們把數據庫從Access改成SqlServer只需要用一個新的CDataAccess類替換現在的即可。在源碼中,就有一個使用了Odbc.Net實現的COdbcDataAccess,用這個替換掉CDataAccess不會對程序中其他部分產生任何影響,我們可以利用Odbc.Net的訪問能力,把數據庫改為Oracle、Forpro等。
三、邏輯層
這個留言本的邏輯層很簡單,由三個類組成,CMessage用來描述一條留言,CReply用來描述一條回復,CReplyCollection集合類用來描述多條回復。
CMessage提供了一個重載的構造函數:
public CMessage(DataRow row)
我們可以用CMessageData中個一個DataRow的數據來初始化一個CMessage對象。
public void FillDataRow(DataRow row)
這個函數則把自身的數據填充進參數中的DataRow對象。我們用類似:
GetMessage().FillDataRow(messageData.AddedNewRow())
這樣的代碼就可以把一條新的留言內容新增到一個CMessageData對象中,其中GetMessage()是頁面上收集用戶填入的數據并返回一個CMessage的一個方法。
public CReplyCollection Replys
這個屬性用來公開對自身這條留言的所有回復。
四、界面層 - 用戶控件
為了方便我們把一個CMessage對象和頁面上顯示出來的一條留言綁定在一起,把一個CReply對象與頁面上顯示出來的一條回復綁定在一起,我們制作兩個UserControl。MessageBlock控件用來顯示一條留言,它通過屬性:
public CMessage Message
來對象公開CMessage接口,我們只需要把一個CMessage對象賦值給這個屬性,就可以讓這個控件顯示CMessage對象所表示的留言的內容。
ReplyBlock控件用來顯示一條回復,同樣通過屬性:
public CReply Reply
來公開一個CReply類型的接口。
在MessageBlock控件中,我們根據對應的CMessage對象的Replys屬性中所包含的回復,通過LoadControl()方法來動態載入ReplyBlock控件,并放置在一個PlaceHolder類型的Web控件中。
五、界面層 - 頁面
現在頁面的顯示非常簡單了,我們在主頁面(default.aspx.cs)中創建一個CMessageData對象,填充數據,再用LoadControl()方法來載入MessageBlock控件來顯示留言就可以了。
CMessageData messageData = CMessageData.FillDataFromDatabase((iPage - 1) * iPageSize, iPageSize);
for(Int32 i = 0; i < messageData.Count; ++i) {
MessageBlock msg = (MessageBlock)LoadControl("MessageBlock.ascx");
msg.Message = new CMessage(messageData.Tables["MessageTable"].Rows[i]);
hldMessage.Controls.Add(msg);
}
以一個功能齊全的留言本來衡量,我們上面構建的留言本缺少刪貼、管理功能,但是只要基礎架構出來,完善和擴展功能是非常簡單的。
上面的留言本展示了一個基礎的程序架構,真正大型程序的架構可能要復雜上很多。比如數據實體類我們可以把字段信息和映射信息放入一個XML文件中,然后我們只需要創建一個通用的數據實體類,通過載入不同的XML文件就可以描述不同的數據實體;在數據復雜的情況下,維護各個數據間的關系也是一個挑戰。
源代碼可以在http://www.86soft.com/clsoft/kaneboy/gbook.zip下載到,如果你要用,記住修改一下AppParameters.xml文件,至少里面連接字符串的Access文件的路徑是需要更改的(你可以干脆在global.asax中用MapPath()來動態得到這個路徑:),CAppParameters.cs文件中的_sAppParameterFileName字符串的值也要根據實際情況作出改變(同樣你可以用MapPath():),然后在IIS中建立一個名為gbook的虛擬目錄來承載這個項目。