Web應(yīng)用架構(gòu)分析之查詢傳遞
在Web應(yīng)用開發(fā)中,最常見也容易變化的一種需求是根據(jù)不同的查詢條件獲取數(shù)據(jù)列表。如何傳遞查詢條件將影響程序應(yīng)對需求變化的能力,一定要在架構(gòu)中重點考慮。
開始時我們使用一堆參數(shù)傳遞查詢條件,比如:
- List<SiteMsg> GetMsgList(int pageIndex, int pageSize, int RecipientId);
結(jié)果,每個不同的查詢都要寫一個接口,產(chǎn)生了一堆接口;查詢條件改變,接口也隨之要改。寫程序最痛苦的事莫過于接口的頻繁變化。
后來使用查詢對像,比如:
- List<SiteMsg> GetMsgList(SiteMsgQuery msgQuery);
這樣,查詢條件改變時,只需修改SiteMsgQuery的定義,接口保持不變。采用這個方法后,寫代碼比之前少了很多痛苦。
但使用這個方法有個地方不爽,完成一次查詢需要進行兩次實例化,一次是查詢對象SiteMsgQuery的實例化,一次是領(lǐng)域?qū)ο骃iteMsgManager(負責業(yè)務(wù)邏輯)的實例化。在博客園程序架構(gòu)中,查詢對象的實例化是在表現(xiàn)層完成的,如果是ajax調(diào)用,json會自動反序列為查詢對象;領(lǐng)域?qū)ο蟮膶嵗诜?wù)層完成。
為了讓代碼寫的更爽一些,我們又進行了嘗試,取消查詢對象SiteMsgQuery,將它的屬性放到領(lǐng)域?qū)ο笾?。這樣減少了一次實例化,只需一次,如果是ajax調(diào)用,可以實現(xiàn)服務(wù)器端“零實例化”。
下面看一下代碼示例:
領(lǐng)域模型的定義:
- [DataContract]
- public class SiteMsgManager
- {
- public SiteMsgManager()
- {
- }
- #region Properies
- [DataMember]
- public int PageIndex { get; set; }
- [DataMember]
- public int PageSize { get; set; }
- [DataMember]
- public int RecipientId { get; set; }
- public List<SiteMsg> List { get; set; }
- #endregion
- public void GetList()
- {
- using (SpaceObjectContext context = new SpaceObjectContext())
- {
- this.List = context.SiteMsgs
- .Where(msg => msg.RecipientSpaceUserId == this.RecipientId)
- .OrderByDescending(msg => msg.id)
- .Skip((PageIndex - 1) * PageSize)
- .Take(this.PageSize)
- .ToList();
- }
- }
服務(wù)實現(xiàn)類(也是WCF的服務(wù)實現(xiàn)):
- public class MsgService : IMsgService
- {
- public List<SiteMsg> GetMsgList(SiteMsgManager siteMsgManager)
- {
- siteMsgManager.GetList();
- return siteMsgManager.List;
- }
- }
UI層調(diào)用代碼(WCF調(diào)用,ASP.NET MVC控制器):
- public class MsgController : Controller
- {
- //ajax調(diào)用
- [HttpPost]
- public ActionResult List(SiteMsgManager msgManager)
- {
- return View("MsgList", GetInboxMsgList(msgManager));
- }
- public ActionResult Inbox()
- {
- SiteMsgManager msgManager = new SiteMsgManager()
- {
- PageIndex = 1,
- PageSize = 30
- };
- return View("Inbox", GetInboxMsgList(msgManager));
- }
- private List<SiteMsg> GetInboxMsgList(SiteMsgManager msgManager)
- {
- int spaceUserId = Util.GetCurrentUser
(System.Web.HttpContext.Current).SpaceUserID;- msgManager.RecipientId = spaceUserId;
- MsgServiceClient client = new MsgServiceClient();
- List<SiteMsg> siteMsgList = client.GetMsgList(msgManager).ToList();
- try { client.Close(); }
- catch { client.Abort(); }
- return siteMsgList;
- }
- }
看看上面供ajax調(diào)用的List方法,不需要進行SiteMsgManager的實例化,系統(tǒng)根據(jù)ajax客戶端傳遞過來的json參數(shù)自動反序列化生成SiteMsgManager對象。
再來看看ajax客戶端代碼:
- function GetMsgList(pageIndex, pageSize) {
- var msgManager = {}
- msgManager.PageIndex = pageIndex;
- msgManager.PageSize = pageSize;
- $.ajaxSettings.dataType = 'plain/text';
- $.ajaxSettings.url = '/msg/list';
- $.ajaxSettings.data = '{"msgManager":' + JSON.stringify(msgManager) + '}';
- $.ajaxSettings.success = function (data) {
- $("#msg_list").html(data);
- };
- $.ajax();
- }
js傳遞的也是一個對像。
整個ajax調(diào)用的流程是這樣的:js對象(msgManager)->json->MsgController(MVC控制器)->代理領(lǐng)域?qū)ο骃iteMsgManager(WCF客戶端代理類的實例)->WCF服務(wù)接口->WCF服務(wù)實現(xiàn)(自動通過反序列化生成領(lǐng)域?qū)ο骃iteMsgManager,并調(diào)用GetList()方法)->領(lǐng)域?qū)ο笸瓿蓸I(yè)務(wù)邏輯操作返回數(shù)據(jù)。
采用這種方法,感覺寫代碼比以前更享受了。我們在實際開發(fā)中也開始使用這種架構(gòu),并根據(jù)實際使用情況進一步改進。
【編輯推薦】