Web应用架构探索笔记 —— 查询
在Web应用开发中,最常见也容易变化的一种需求是根据不同的查询条件获取数据列表。如何传递查询条件将影响程序应对需求变化的能力,一定要在架构中重点考虑。
开始时我们使用一堆参数传递查询条件,比如:
List<SiteMsg> GetMsgList(int pageIndex, int pageSize, int RecipientId);
结果,每个不同的查询都要写一个接口,产生了一堆接口;查询条件改变,接口也随之要改。写程序最痛苦的事莫过于接口的频繁变化。
后来使用查询对像,比如:
List<SiteMsg> GetMsgList(SiteMsgQuery msgQuery);
这样,查询条件改变时,只需修改SiteMsgQuery的定义,接口保持不变。采用这个方法后,写代码比之前少了很多痛苦。
但使用这个方法有个地方不爽,完成一次查询需要进行两次实例化,一次是查询对象SiteMsgQuery的实例化,一次是领域对象SiteMsgManager(负责业务逻辑)的实例化。在博客园程序架构中,查询对象的实例化是在表现层完成的,如果是ajax调用,json会自动反序列为查询对象;领域对象的实例化在服务层完成。
为了让代码写的更爽一些,我们又进行了尝试,取消查询对象SiteMsgQuery,将它的属性放到领域对象中。这样减少了一次实例化,只需一次,如果是ajax调用,可以实现服务器端“零实例化”。
下面看一下代码示例:
领域模型的定义:
[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();
}
}
服务实现类(也是WCF的服务实现):
public class MsgService : IMsgService
{
public List<SiteMsg> GetMsgList(SiteMsgManager siteMsgManager)
{
siteMsgManager.GetList();
return siteMsgManager.List;
}
}
UI层调用代码(WCF调用,ASP.NET MVC控制器):
public class MsgController : Controller
{
//ajax调用
[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调用的List方法,不需要进行SiteMsgManager的实例化,系统根据ajax客户端传递过来的json参数自动反序列化生成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调用的流程是这样的:js对象(msgManager)->json->MsgController(MVC控制器)->代理领域对象SiteMsgManager(WCF客户端代理类的实例)->WCF服务接口->WCF服务实现(自动通过反序列化生成领域对象SiteMsgManager,并调用GetList()方法)->领域对象完成业务逻辑操作返回数据。
采用这种方法,感觉写代码比以前更享受了。我们在实际开发中也开始使用这种架构,并根据实际使用情况进一步改进。
注:这篇随笔只是我们在探索博客园Web应用架构过程中的笔记,并不代表这是更好更合理的方法。写出来一是为了分享,二是帮助自己更好的思考,三是记录架构演变的过程。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
2008-02-13 《环球企业家》:鲍尔默的独角戏
2004-02-13 准备增加"Highlighting .NET code from FreeTextBox"功能