Ajax[转自JeffreyZhao]不妨来做只尝试:UpdatePanel for ASP.NET MVC

初稿地址:http://www.cnblogs.com/JeffreyZhao/archive/2008/04/27/try-to-build-an-updatepanel-for-asp-dot-net-mvc.html

事先来作一样搭牢骚。

  其实就是平篇迟发布即2单月的文章。事实上在ASP.NET MVC Preview
2发布前我便既拿即时首文章的兼具情节准备了了。当时纪念,就相当Preview
2发布吧,而真的使Preview
2发布后倒以懒得进行移植——移植了今后却还要懒得写篇。这无异拖延就是走近2只月,毫无长进。可能工作相当其他业务实在多矣几,但是扪心自问,也并没有忙到好。时间屡屡都是于点点滴滴间浪费的。唉,可能是自视太强,越来越不乐意写有习以为常的介绍性文章,导致可写的物大大缩减。不过话说回来,其实打算写的,甚至数说过如果描绘得东西也并无掉,为什么就即从未动笔呢?其实还是一个“懒”字——当年之卧薪尝胆劲儿到哪里去了也?

  言归正传。先解释一下标题,什么是“UpdatePanel for ASP.NET
MVC”呢?ASP.NET AJAX中之UpdatePanel相信大家都有了解。可惜的凡,ASP.NET
MVC框架的出生“毁灭”了汪洋根据PostBack的控件,首当其冲地或就是UpdatePanel了。如果没有PostBack,UpdatePanel就去了所有意图,甚至不如部分绑定控件,至少它还能够用于展示。为UpdatePanel长吁短叹之后,我们不由自主又起想UpdatePanel的优势:“透明”。在UpdatePanel的扶植下,实现AJAX操作对于开发人员几乎全盘透明。我们如果开的特是将需AJAX更新的内容用UpdatePanel包装起来,一切都是那么优雅。

  我们可否以ASP.NET
MVC中解救UpdatePanel呢?也许是好的吧,但当时重复像是一个“不容许完成的任务”。我莫是风传被的阿汤哥,因此又为ASP.NET
MVC量身定制一个AJAX解决方案似乎尤为有效。虽然我们不见面苛求一个初大事物从降生开始就趋向完美,但哪怕只有是一个原型,它为非得严格恪守的部分准绳:

  • 不行破坏MVC中的磋商(协作,职责等等)
  • 对开发人员尽可能地透明

  Nikhil Kothari已提出了他当ASP.NET
MVC框架下之AJAX解决方案。如果您还未打听他的做法,那么我事先以此展开一些包括。Nikhil扩展了Controller使之支持一种Ajax操作,于是我们当代码中便好描绘如下代码:

public class
TaskListController : AjaxController {
    …
    public void CompleteTask(int taskID) {
        if (String.IsNullOrEmpty(Request.Form[“deleteTask”]) == false) {
            InvokeAction(“DeleteTask”);
            return;
        }
 
        Task task =
_taskDB.GetTask(taskID);
        if (task != null) {
            _taskDB.CompleteTask(task);
        }
 
        if (IsAjaxRequest) {
            if (task != null) {
                RenderPartial(“TaskView”,
task);
            }
        }
        else {
            RedirectToAction(“List”);
        }
    }
    …
}

  与AjaxController类似,Nikhil也也ViewPage和ViewControl提供了有些扩展方法,因此目前以View(List.aspx)中我们不怕能够看到如下的代码:

<div id=”taskList”>
    <% foreach (Task task in Tasks) { %>
        <div>
          <% this.RenderPartial(“TaskView”, task);
%>
        </div>
    <% } %>
</div>

  以View和Controller中还存在对RenderPartiel方法的调用,它们的用意就是是往客户端输出一个“Partial
Template”生成的HTML代码。而在ASP.NET MVC的默认配置中,Partial
Template即为User Control。而当TaskView这个Partial
Template中好看看有些拉方法:

<div id=”taskItem<%= Task.ID %>” class=”taskPanel”>
<% Ajax.Initialize(); %>
<%
this.RenderBeginAjaxForm(
      Url.Action(“CompleteTask”),
      new {
          Update = “taskItem” + Task.ID,
          UpdateType = “replace”,
          Completed = “endUpdateTask”});
%>

    <input type=”hidden”
name=”taskID” value=”<%= Task.ID %>” />
    <input type=”submit”
class=”completeButton” name=”completeTask” value=”Done!”
/>
    <input type=”submit”
class=”deleteButton” name=”deleteTask” value=”Delete” />
    <span><%= Html.Encode(Task.Name) %></span>
 
<% this.RenderEndForm();
%>
<% Ajax.RenderScripts();
%>
</div>

  这些援助方法的来意是格外成有触发AJAX更新的签及脚本,当用户点击RenderBeginAjaxForm与RenderEndForm方法变的tag之间的交给按钮时,网页将会朝服务器端发出一个AJAX请求,而服务器端的Action并最后见面透过RenderPartial方法输出一个Partial
Template生成的HTML。服务器端最终输出的HTML将会晤受调换或丰富到页面的某个元素外。这就是形成了一个AJAX效果。这个解决方案于一些方面看上去十分挺,尤其是变化的代码可以增长到某元素中,而不单单是如同UpdatePanel的交替,例如Nikhil在外的例子中虽使了之特点实现了一个加上效果。不过假如应用之前提出的法来衡量的话,似乎是解决方案并无老可以。

  原因很粗略,因为未足够透明。

  也起品看,Controller中之逻辑不欠根据一个请求AJAX与否而进展不同处理(Nikhil的缓解方案以RenderPartial来顶替RenderView为AJAX操作进行输出),因此这个解决方案破坏了MVC的任务。我莫这样认为,但是我望能到位这或多或少,因为成功及时同一接触就表示绝对的晶莹。绝对透明则意味Controller将一个应用程序是否AJAX的决定权全交由了客户端,这点非常好,因为AJAX完全是一个表现层的定义。ASP.NET
AJAX中的UpdatePanel在即时地方的展现可圈可点(虽然还多不够全面),因此自最终决定吧也ASP.NET
MVC开发同缓缓类似UpdatePanel的零部件。值得庆幸之是,ASP.NET
MVC默认使用WebForm页面作为视图模板,在这强大的模子之下,构建有如此一个AJAX解决方案(的本色)似乎并无十分困难。

  我用以此控件命名也MvcAjaxPanel。MvcAjaxPanel与UpdatePanel最充分之区别在后者接收的凡PostBack,而前者接收的单纯是常见的HTTP请求。Post“Back”意味着Post过后归了本的Page,而ASP.NET
MVC的求往往会于指引至不同的页面。因此怎样跨页面进行内容更新是MvcAjaxPanel首要解决的题目。最终我选了为每个MvcAjaxPanel指定一个UpdateAreaID的做法。

<mvc:MvcAjaxPanel runat=”server” ID=”mvcAjaxPanel” UpdateAreaID=”Header”>
    …
</mvc:MvcAjaxPanel>

  当页面向服务器端发出一个AJAX请求时用会有意无意页面被的UpdateAreaID信息,而服务器端的Action并无见面发现及当时或多或少,因此还是以寻常逻辑指定一个视图模版并出口HTML。不过,如果视图模板被之MvcAjaxPanel发现这个要实际上是一个契合约定的AJAX请求(请小心,只有View组件意识及及时是个请求的性),则会使用新的法子来替换标准的出口。这时候模板就会基于客户端传递过来的UpdateAreaID,寻找页面上有所同样属于性值的MvcAjaxPanel,有选择性地出口内容。在客户端就会见有照应之JavaScript代码接收服务器端的数额,并且更新页面中之应和区域。

  很明确,MvcAjaxPanel的办事原理及UpdatePanel有好多相似之远在,也到位了必然水平上的透明。而且跟Nikhil的化解方案比,一个十分重要的优势就是足以同样潮创新页面被的基本上独区域——其实这也就是UpdatePanel的性状有。而且这种对Controller透明的做法又发出一个原始的特点,那就算是力所能及轻松地以匪支持AJAX的浏览器被使传统的方式切换页面。

  服务器端的实现原理并无复杂,不过作为解决方案的旁一个生死攸关部分,如何在客户端触发一个AJAX提交也是一个值得沉思的话题。UpdatePanel的艺术可谓“全自动”:页面加载时将会晤拿服务器端的Trigger信息输出到客户端,然后以客户端截获form的交由事件,并经过UniqueID或DOM结构相当措施来判定这次提交是否该转会为AJAX方式。不过当一个ASP.NET
MVC页面中几无见面面世有PostBack的元素,相反会有恢宏的寻常链接,它们才是AJAX更新的主要截获目标。

  也是我提供了有JavaScript代码,截获一个链接原本的对象地点并拿其转化为一个AJAX请求。我以此通过示范中的代码来展示这种应用办法(这个示例源于Brad
Abrams提供的ASP.NET
MVC示例,不过自己放弃了Northwind数据库与Entity
Framework,取而代之的是XML数据及从定义的简要Model。此外,我也将该移植到ASP.NET
MVC框架的0416 Build中):

<%  foreach (var
category in this.ProductCategories)
    { %>
        <li>
            <%= Html.ActionLink<ProductsController>(
                    c => c.List(category, 1),
                    category,
                    new { onclick = “mvcAjax.get(this, event)”
}
)%>
        </li><%
    } %>

  这段代码来分类列表页。与AJAX改进前的代码相比,唯一的分别就是是外加指定了元素的onclick事件(加粗部分)。在onclick事件实施中,这个链接默认的跳转行为将于撤销,取而代之的凡一个AJAX请求,请求的目标虽是ProductsController中名为List的Action。

  我们得采取方面的法回应常见链接,那么又欠怎么以一个客户端from的付出行为呢改成AJAX操作为?以下依旧是现身说法中之代码:

<form method=”post”
    action=”<%= Url.Action(“Update”, new { id =
this.Product.ProductID }) %>”
    onsubmit**=”mvcAjax.submit(this,
event);”**>
 
    <table>
        <tr>
            <td>Name:</td>
            <td><%= Html.TextBox(“Name”, this.Product.Name) %></td>
        </tr>
        …
    </table>
 
    <input type=”submit”
value=”Save” />
</form>

  在缴获了form的submit事件之后,客户端将会晤征集该form中的具有input、select等价值,组成一个伸手的body,并且为HTTP
POST的法门发生一个AJAX请求。余下的作业与之前就是从不啊分别了。

  以及UpdatePanel相比,MvcAjaxPanel的客户端截获方式可谓“纯手工”,但是我并不认为这会招致什么问题。ASP.NET
MVC强调的便是职责分开,而这种分离并不只体现在代码上,也体现在开发人员的职责及。在付出ASP.NET
MVC应用程序时,负责View的是前端开发工程师,对她们来说JavaScript与AJAX可谓是还熟悉不了之技术。在合时的地方手动编写一些JavaScript调用反而会叫他们得到最好之自由性。例如在前的代码示例中,调用mvcAjax.get或mvcAjax.submit方法时完全可以在内外自由地加入额外操作还是条件判断。这即无见面像用UpdatePanel时,如果用使用JavaScript提交一个AJAX更新,还需要依靠不登大雅之堂的trick。

  也刚以这样,Nikhil提出的化解方案特别不利,它亦可同前台开发人员的自定义逻辑进行灵活地构成。此外,通过看ASP.NET
MVC框架0416 Build的代码,我意识以新本子的ASP.NET
MVC中似乎以会晤放这种AJAX解决方案了——不了这也真可微软的一贯做法,不是为?:)

  这个AJAX解决方案原型的利用方法跟行事原理已经描述了了,如果你对那现实落实感兴趣,或者想亲身尝试一下,可以下载文章最后的附件。附件中的化解方案包含三个种类,MvcAjax为提供MvcAjaxPanel的档次,而MvcWebApp是一个家常的ASP.NET
MVC示例程序,而MvcAjaxWebApp自然就是添加AJAX效果下的结果了。在示范中,我还以Master
Page中定义之食谱(即页面左侧的菜谱)里显示了千篇一律片当前岁月,这是为反映MvcAjaxPanel的“一软提交,多处更新”的风味。

  不过要强调的凡,这仅是只原型。或者说就才是同样种实现达标尝,在众多细节方面连没有犯极端多追求。如果一旦变为一个宏观之AJAX解决方案,还需要发大量之改善。例如:

  • 供一些客户端的hook供前台开发人员使用(如提交前、接受后、或者处理一个交给还没返回,客户端就发起另一个央的景象等等)。
  • 重强硬的功用,更好之支付体验(如客户端触发机制)
  • 特别处理
  • 支持脚本
  • 支持跳转(Redirection)

  此外,作为面向ASP.NET
MVC特有的AJAX解决方案,也有局部格外的问题亟待考虑。最特异的题材之一即是在行使ASP.NET
MVC时死少用模板控件,而重复多的使页面被的大循环,那么什么样让MvcAjaxPanel在循环内容生效?我吗发出过部分想方设法,但是只要要真确定下最终的贯彻方式,很多东西还用更为考虑。如果你对于这个AJAX解决方案有啊建议还是外任何想法,也要尽快告诉自己。

  最后重复说一样件有趣的作业:在自家实现了是原型之后的某某同天,忽然发现及是控件似乎不光可以吗ASP.NET
MVC使用,也会用于一般的WebForms应用程序。这真的是一个驱动人始料不及的觉察。

 

附件:源代码及下示例

Tag标签: ASP.NET
MVC,UpdatePanel,MvcAjaxPanel,AJAX

相关文章