.Net环境下基于Ajax的MVC方案
1、问题背景现在,越来越多人开始尝试基于Ajax进行无刷新的Web开发,不过,在.Net环境下,应用Ajax并不是非常方便,这主要可能是由以下一些原因造成的:
·由于Ajax基于javascript的本质,使得开发者必须对javascript非常了解,起码,其javascript能力足以实现对callback返回内容对页面的更新,所以开发的门槛就有一定程度的上升
·当基于Ajax机制进行开发时,原有的基于postback方式下时,asp.net由后台逻辑代码(Model),aspx页面(View)、aspx.cs(Controller)构成的MVC构架其实失效了,当callback返回数据时,要么在client端用javascript解析返回内容以实现更新,要么则必须在server端构造好比较完整的html代码,再直接由javascript将该构造好的html设置给某个页面对象,很显然,这样一来,要实现一个最简单的callback功能,都要不少代码,并且是相对比较乱的代码,即使在即将到来的asp.net2.0该问题依然不会得到有效解决
2、本文目的
本文旨在充分利于现有的asp.net本身的特点和ajax的特性,提出一个用于在asp.net环境下进行基于ajax的web开发的MVC方案,以实现以下主要目的:
·Asp.Net环境下用于Ajax的清晰的MVC构架
·降低编程人员对过多javascript编码的依赖以降低编程门槛
·灵活的支持ajax模式下的常用开发方式
3、问题分析
如何实现以上几个主要目的呢?
1)要对xmlhttprequest对更良好的封装,以使调用方式更简单;
2)尽量在server端进行更新数据的构造,但是也要避免每次返回数据都手工构造,因此,就想到可以充分使用UserControl,由UserControl作为"View",对应的由ascx.cs文件作为"Controller",这样构成的MVC也是比较清晰的;
4、问题解决
基于以上思想,本人实现了以下一个组类库以简化该过程:
源码及范例下载
代码简析:
1)首先在client端,AjaxHelper.js封装了xmlhttprequest,并提供一个将现有的<form>序列化为形如param1=v1¶m2=v2&...形式用于post的参数;
Updater(ajaxTemplate, output, params, onComplete)函数,用于实现一次callback调用
ajaxTemplate(必选):指定执行需要功能的UserControl路径
output(可选):填充返回数据的指定标签的引用或ID值
params(可选):形如param1=v1¶m2=v2&...的post参数
onComplete(可选):可用于对返回数据进行特殊处理的回调函数,函数格式function(str),str为返回的数据
SerializeForm(form)函数,用于序列化<form>
form:可以是对指定<form>的引用或ID值
2)在server端,Ajax.aspx文件封装了对由客户端ajaxTemplate指定的UserControl的调用,其余的具体逻辑功能则在特定的UserControl及其ascx.cs内实现;
3)这样,具体执行一次callback时,编程人员只需在页面引用AjaxHelper.js,并在指定的位置通过javascript:Updater(ajaxTemplate, output, params, onComplete)进行调用,如果需要对某一form进行提交,则可调用javascript:SerializeForm(form)序列化该form并传给params,当然也可以手动构造params,并指定将返回数据通过设置output应用的页面或通过onComplete自定义处理。
4)由于充分使用UserControl,意味着,可以充分利用asp.net原有的web服务器端控件和数据绑定机制,这样其实,已经很大程度上简化了返回数据的构造,在ascx.cs中,通过Request.Form[ParamName]就能访问到client端传入的params,再访问逻辑代码获取源数据。
5、范例
包含在源码中的范例实现了一个简单的无刷新获取博客园首页内容到一个textarea的功能,详见源码!
部分范例源码:
Default.aspx
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ContractedBlock.gif)
![](http://teddyma.vcblog.net/Images/dot.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/dot.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ContractedBlock.gif)
![](http://teddyma.vcblog.net/Images/dot.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
AjaxHelper.js摘要:
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
UserControl GetPageSrc.ascx.cs摘要:
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ContractedBlock.gif)
![](http://teddyma.vcblog.net/Images/dot.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://teddyma.vcblog.net/Images/dot.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://teddyma.vcblog.net/Images/dot.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/InBlock.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](http://teddyma.vcblog.net/Images/OutliningIndicators/None.gif)
Enjoy!
//文章结束
posted on 2005-06-11 18:55 Teddy's Knowledge Base 阅读(8916) 评论(40) 编辑 收藏 引用 收藏至365Key 所属分类: Ajax
评论
写得不错:)
关于Ajax技术的讨论,我建议你可以和李锟(MSN:unruly_wind@sina.com)多多交流,他对此已经有很多的经验,尤其是对http://maps.google.com的应用研究,当然,如果能够得到你的联系方式更好了 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-13 14:36 ahnan
有研究过 ASP.NET 2.0 中的 Script Callback 吗? 有研究过 Ajax.NET, Ajax Library for .NET 吗? 我觉得你可以从上述方法中了解更多ajax 在 .NET 的应用实践。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-13 14:42 Teddy's Knowledge Base
to ahnan:
你说的两个东西都是对xmlhttprequest的不同封装实现而已,我都花时间研究过,这两个封装和我的代码在callback机制上本质是一样的,我的代码中的ajax封装,基于prototype1.2的一个ajax实现,是与后台语言独立的,调用方式也比你说的这两个简单,并且我的框架可以很容易的移植到非.net平台。
而最重要的是,你说的这两个ajax实现,会造成本文要解决的问题之一asp.net原有的mvc构架在这两种应用模式下会被破坏,我的框架的设计初衷就是解决这一问题,重新搭建一个清晰的mvc。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-14 00:01 逐灵
Ajax Library for .NET 我刚刚看过它的一些功能演示和简单的使用方法,
第一感觉就是必须在Client端进行数据的绑定,觉得这比较麻烦。
刚刚看过Teddy的,使数据在Server端绑定,确定方便了不少。
不过刚刚没有调试成功,现在正在找原因。
个人愚见,没仔细研究过,说错了请指正。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-14 00:56 逐灵
看了半天终于明天了Js里面的运行过程,
只是,
好像没办法成功访问ajdx.aspx文件。
这是什么原因呢? 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-14 01:21 逐灵
终于知道是怎么回事了。
js里面默认是用'Post'方式传递参数的,可是,不知道是因为什么原因,合使用Post参数导致根本无法访问到ajax.aspx文件,于是我改成用'get'方式,就可以了。请问这是什么原因呢?
发现'post'不行是因为我期间把请求源码的地址改为'http://www.skycn.com',它会返回一个关于'post'的错误页面,于是就发现了这个问题。
你们调试是不是这样的呢? 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-14 09:37 Teddy's Knowledge Base
照道理get可以post应该也可以的,用post的话好处是可以避免用户直接从地址栏访问ajax.aspx,当然,也可以改一下js使得可以在get和post之间进行选择。
你的情况我没遇到过,不过,通过get方式传递对参数长度有限制,一般应该在255个字符之内,post应该能大一点,你可以再试试能不能找到post错误的真正原因,找到原因的话希望能共享一下! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 16:12 jlzhou
感谢Teddy's share!
Net环境下基于Ajax的MVC方案,有没有更新版呢? 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 16:21 Teddy's Knowledge Base
目前还没有更新的版本,我的一个个人项目会完全基于该方案进行开发,会在开发的过程中不断的完善这个方案,目标是能达到像
http://backbase.com/index.php
这个网站这样的用户体验,由于我这个方案数据的填充构造基于UserControl,可以更多利用asp.net原有控件的数据绑定能力,代码量应该能减少不少! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 16:39 jlzhou
调试不能通过,只有一个loading...显示就不动了。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 16:52 Teddy's Knowledge Base
根据你调试机器的网速,loading的时间可能有长短,只要能编译通过,就应该能正常运行的,我这儿在一个新的环境又试了下完全没问题,建议按如下步骤调试该范例:
1、下载并解压缩到某路经比如:d:/AjaxHelper
2、为AjaxHelper目录建一个虚拟目录AjaxHelper
3、用VS.Net打开AjaxHelper.sln
4、编译
5、将Default.aspx设为起始页
6、按F5运行
7、页面显示loading...时请稍作等待,此时正在下载指定的网页源码
8、下载源码完毕页面会显示源码内容
回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 16:56 jlzhou
感谢指点,我就是按照上述步骤做的,可是还是不行,我再研究一下。
再次感谢! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 20:10 jlzhou
又折腾了半天,死活都不行!我真笨! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 20:49 Teddy's Knowledge Base
不要气馁,你可以单步调试一下,包括对js,整个工程除了js之外手写的有效的代码可能还不到10行,应该比较容易能找出原因的。
或者说说看你主要在哪一步出错,是编译不通过,还是运行时脚本报错呢? 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 21:25 jlzhou
哪也没报错,就是浏览器只有loading显示,然后再也没有任何动静了。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 21:29 jlzhou
我刚刚修改了ajax.aspx的文件名,也不报错,看来没有callback来访问这个文件。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 21:31 jlzhou
基本锁定是js的问题。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 21:48 jlzhou
我的IE版本是6.0.2800.1106.xpsp2 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 21:53 Teddy's Knowledge Base
那确实比较奇怪,前面有位朋友也遇到过比较奇怪的问题,你参考他说的解决办法试试,另外,你也可以看看默认情况下浏览default.aspx的ie的encoding是什么,可以试试encoding在gb2312和utf-8间切换试试。
另外在就是你可以在页面的Updater函数前后加上try{}catch(ex){window.alert(ex)},看看是什么错误! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 22:10 jlzhou
还是不行,加上
try{Updater('AjaxTemplate/GetPageSrc', 'view2', 'url=http://www.smartprise.com');}catch(ex){window.alert(ex)}
也不报错,就是loading没完。
我的QQ是9842766 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 22:13 jlzhou
默认情况下浏览default.aspx的ie的encoding是utf8,试试encoding在gb2312和utf-8间切换,IE右上角的小窗口图标动个不停,IE窗口里什么都没有。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-15 22:17 Teddy's Knowledge Base
建议你还是对js进行下单步调试,这样执行js过程中的错误都能被捕获,需要先在ie的选项里开启脚本调试,然后再vs.net里面对js设断点就可以了。不好意思,因马上有点事要离开现在不能和你qq交流,如果还解决不了,明天白天和你qq吧,不过我很少qq,一般只用msn。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-16 09:06 蓝色闪电
呵呵,原来就是JS+XmlHttp+.NET的组合!
用了这个技术很久,突然今天发现它有个新名字:Ajax,有意思!
上面的兄弟:
try{Updater('AjaxTemplate/GetPageSrc', 'view2', 'url=http://www.smartprise.com');}catch(ex){window.alert(ex)}
没用的,访问不到页面并不是JS代码发生异常,catch不到错误的! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-16 10:19 Teddy's Knowledge Base
为AjaxHelper又写了点使用范例,请访问
http://www.cnblogs.com/teddyma/archive/2005/06/16/175298.html 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-19 11:48 microhf
好东西呀 回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-20 11:26 Teddy's Knowledge Base
最近更新AjaxHelper0.4,新版本兼容0.3并新增支持Sps下的WebPart开发
http://www.cnblogs.com/teddyma/archive/2005/06/19/176859.html
回复
# re: .Net环境下基于Ajax的MVC方案 2005-06-30 13:18 tangle
调试成功,非常好用,感谢共享 回复
# re: .Net环境下基于Ajax的MVC方案 2005-07-03 09:58 思源
有发觉吗?用Ajax做网站不能够很好的被搜索引擎检索,虽然是个很好的技术 回复
# re: .Net环境下基于Ajax的MVC方案 2005-07-03 11:29 Teddy's Knowledge Base
@思源:
是不是search egine friendly的问题,其实看你的整个网站结构设计,比如,我可以通过site map和url rewrite重写的形式暴露整个站点的页面结构给搜索引擎,完全可以达到需要的效果! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-07-03 12:53 思源
是的,不过觉得Ajax在OA或站点后台方面,可以带来不少好处,个人观点 回复
# re: .Net环境下基于Ajax的MVC方案 2005-08-19 11:21 strea
是不是search egine friendly的问题,其实看你的整个网站结构设计,比如,我可以通过site map和url rewrite重写的形式暴露整个站点的页面结构给搜索引擎,完全可以达到需要的效果! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-08-23 20:44 卡卡.net
提供了OA开发更好的用户体验,好! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-09-20 20:10 larc
God!我试了一下,变一次两分半!这时间再烂的服务器也刷过来了~汗! 回复
# re: .Net环境下基于Ajax的MVC方案 2005-12-17 09:58 蛙蛙池塘
准备到你这里学习一下ajax,用户体验很重要呀。 回复
# re: .Net环境下基于Ajax的MVC方案 2005-12-22 11:46 MrXie
.Net推出来以前,曾经用ASP来应用XMLHTTP, 虽然好(用户感受),
但不能后退.
而且也不知道其它浏览器是否支持XMLHTTP 回复
# re: .Net环境下基于Ajax的MVC方案 2005-12-24 17:13 fx_blog
好慢啊 回复
# re: .Net环境下基于Ajax的MVC方案 2006-03-22 11:04 李晓
我和jlzhou遇到的问题一样!就是LOADING
什么都不做!奇怪呢!JS也没问题 回复
# re: .Net环境下基于Ajax的MVC方案 2006-05-03 13:41 rainpher
teddy 你好
很赞同你的解决方案,想和你交流一下在这样的模式下如何开发用户控件的问题
我想实现一个页面局部刷新的效果 回复
# re: .Net环境下基于Ajax的MVC方案 2006-05-03 13:45 Teddy
对于用户控件,自然也是可以用这个模式开发的,和页面是没什么区别的,你只要定义一些专门用于数据更新的辅助的usercontrols作为ajaxtemplate.
回复
# re: .Net环境下基于Ajax的MVC方案 2006-08-22 13:49 GouGou
SerializeForm 没有这个函数的实例 不会用呀~~~ 回复