• ASP.NET MVC 4 (八) URL链接和Ajax帮助函数


    使用帮助函数创建链接

    MVC提供一些帮助函数创建链接,这些函数根据路径映射表自动调整生成的URL:

    说明 示例 输出结果
    应用程序相对URL Url.Content("~/Content/Site.css")  /Content/Site.css
    到控制器action的链接 Html.ActionLink("My Link", "Index", "Home") <a href="/">My Link</a> 
    Action的URL Url.Action("GetPeople", "People") /People/GetPeople 
    使用路径映射的URL Url.RouteUrl(new {controller = "People", action="GetPeople"})  /People/GetPeople 
    使用路径映射的链接

    Html.RouteLink("My Link", new {controller = "People", action="GetPeople"})

    <a href="/People/GetPeople">My Link</a>
    命名路径映射的链接

    Html.RouteLink("My Link", "FormRoute", new {controller = "People", action="GetPeople"})

    <a href="/app/forms/People/GetPeople">My Link</a> 

    使用MVC Unobtrusive Ajax

    MVC内建基于jQuery的unobtrusive Ajax的支持,之所以称之为unobtrusive Ajax是因为不像常规Ajax那样大量使用XML。要使用unobtrusive Ajax,首先需要在web.config的 configuration/appSettings一节开启UnobtrusiveJavaScriptEnabled支持:

    ... 
    <configuration> 
    <!-- other elements omitted for brevity --> 
    <appSettings> 
    <add key="webpages:Version" value="2.0.0.0" /> 
    <add key="webpages:Enabled" value="false" /> 
    <add key="PreserveLoginUrl" value="true" /> 
    <add key="ClientValidationEnabled" value="true" /> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
    </appSettings> 
    <!-- other elements omitted for brevity --> 
    </configuration> 
    ... 

    同时我们需要引用相关的javascript文件,可以把对这些脚本文件的引用放到布局文件_layout.cshtml中:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>@ViewBag.Title</title>
        <link href="~/Content/Site.css" rel="stylesheet"/>
        <script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
        <script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
    </head>
    <body>
        @RenderBody()
    </body>
    </html>

    jquery-1.7.1.min.js为jQuery的核心库,jquery.unobtrusive-ajax.min.js则提供Ajax功能(基于jquery库),文件名中的.min表示几乎不可能调试的缩减版本,可以在开发时使用非.min版本,发布时再采用.min版本。

    使用Unobtrusive Ajax表单

    下面以实例演示如何使用Ajax表单,从控制器开始:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using HelperMethods.Models;
    namespace HelperMethods.Controllers
    {
        public class PeopleController : Controller
        {
            private Person[] personData = { 
    new Person {FirstName = "Adam", LastName = "Freeman", Role = Role.Admin}, 
    new Person {FirstName = "Steven", LastName = "Sanderson", Role = Role.Admin}, 
    new Person {FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User}, 
    new Person {FirstName = "John", LastName = "Smith", Role = Role.User}, 
    new Person {FirstName = "Anne", LastName = "Jones", Role = Role.Guest} 
    };
            public ActionResult Index()
            {
                return View();
            }
            public PartialViewResult GetPeopleData(string selectedRole = "All")
            {
                IEnumerable<Person> data = personData;
                if (selectedRole != "All")
                {
                    Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
                    data = personData.Where(p => p.Role == selected);
                }
                return PartialView(data);
            }
            public ActionResult GetPeople(string selectedRole = "All")
            {
                return View((object)selectedRole);
            }
        }
    }

    GetPeopleData()方法根据选择的角色过滤Person列表,返回一个分部视图,对应的GetPeopleData.cshtml:

    @using HelperMethods.Models
    @model IEnumerable<Person>
    
    @foreach (Person p in Model) {
        <tr>
            <td>@p.FirstName</td>
            <td>@p.LastName</td>
            <td>@p.Role</td>
        </tr>                
    }

    在Getpeople视图中我们调用GetPeopleData()同时创建一个Ajax form: 

    @using HelperMethods.Models
    @model string
    @{
        ViewBag.Title = "GetPeople";
        AjaxOptions ajaxOpts = new AjaxOptions
        {
            UpdateTargetId = "tableBody"
        };
    }
    <h2>Get People</h2>
    <table>
        <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>
        <tbody id="tableBody">
            @Html.Action("GetPeopleData", new { selectedRole = Model })
        </tbody>
    </table>
    @using (Ajax.BeginForm("GetPeopleData", ajaxOpts))
    {
        <div>
            @Html.DropDownList("selectedRole", new SelectList(new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
            <button type="submit">Submit</button>
        </div>
    } 

    Ajax.BeginForm()创建一个Ajax form,使用AjaxOptions对象作为参数,生成的HTML结果:

    ... 
    <form action="/People/GetPeopleData" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody"id="form0" method="post"> 
    ... 

    浏览器请求GetPeople页面时jquery.unobtrusive-ajax.js扫描data-ajax=true的单元,以此确认这是一个ajax的表单,点击提交时不刷新整个页面,而是用从/people/getpeopledata返回的结果替换tablebody的内容。

    Ajax options

    AjaxOptions控制向服务器异步请求时的方式,包含这些属性:

    属性 说明
    Confirm 在开始异步请求时向用户显示一条消息以确认
    HttpMethod 设置请求的HTTP方法,必须是get或者post
    InsertionMode 如何嵌入服务器结果返回的HTML,可以是InsertAfter、InsertBefore、Replace(默认)
    LoadingElementId 指定Ajax请求时要显示的Loading单元元素ID
    LoadingElementDuration Loading元素动画显示的时长
    UpdateTargetId 请求返回结果要插入的元素ID
    Url Ajax表单提交的URL

    上面的GetPeople视图Ajax form提交的URL是/People/GetPeopleData,如果用户禁止了java脚本,提交form返回的结果会只是GetPeopleData分部视图,我们可以直接在ajaxOptions指定ajax请求的URL来解决: 

    @using HelperMethods.Models
    @model string
    @{
        ViewBag.Title = "GetPeople";
        AjaxOptions ajaxOpts = new AjaxOptions
        {
            UpdateTargetId = "tableBody",
            Url = Url.Action("GetPeopleData"),
            LoadingElementId = "loading",
            LoadingElementDuration = 1000,
            Confirm = "Do you wish to request new data?"
        };
    }
    <h2>Get People</h2>
    <div id="loading" class="load" style="display:none">
        <p>Loading Data...</p>
    </div>
    <table>
        <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead>
        <tbody id="tableBody">
            @Html.Action("GetPeopleData", new { selectedRole = Model })
        </tbody>
    </table>
    @using (Ajax.BeginForm(ajaxOpts))
    {
        <div>
            @Html.DropDownList("selectedRole", new SelectList(
    new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
            <button type="submit">Submit</button>
        </div>
    }

    生成的表单HTML:

    ... 
    <form action="/People/GetPeople"data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" data-ajax-url="/People/GetPeopleData"id="form0" method="post"> 
    ... 

    这样表单提交的URL依然是/People/GetPeople,即使禁止了java脚本返回的仍然是GetPeople页面,ajax请求的URL通过data-ajax-url指定为/People/GetPeopleData。我们还设置 AjaxOptions.LoadingElementId为Loading,这是一个diplay:none风格的DIV元素,它只在AJAX异步请求时显示一秒钟(LoadingElementDuration = 1000)。AjaxOptions.Confirm= "Do you wish to request new data?" ,在每次Ajax请求时都会弹出网页Message对话框询问(对话框消息为这里设定的"Do you wish to request new data?")。

    Ajax链接

    上面的例子中我们使用表单提交数据,如果是使用链接做ajax异步请求可以这样操作:

    ...
    <div> 
    @foreach (string role in Enum.GetNames(typeof(Role))) { 
      <div class="ajaxLink"> 
      @Ajax.ActionLink(role, "GetPeopleData", 
        new {selectedRole = role}, 
        new AjaxOptions {UpdateTargetId = "tableBody"}) 
      </div> 
    } 
    </div> 
    ...

    这里对role枚举中每个元素生成一个链接,生成的链接元素类似:

    ... 
    <a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#tableBody" href="/People/GetPeopleData?selectedRole=Guest">Guest</a> 
    ... 

    点击某个链接时ajax返回的HTML数据会用于替换tableBody元素,和使用表单提交ajax请求效果一样。同样如果禁用了java脚本,返回的结果会只是getpeopledata分部视图,我们可以这样改进:

    <div> 
    @foreach (string role in Enum.GetNames(typeof(Role))) { 
      <div class="ajaxLink"> 
      @Ajax.ActionLink(role, "GetPeople", 
        new {selectedRole = role}, 
        new AjaxOptions { UpdateTargetId = "tableBody", Url = Url.Action("GetPeopleData", new {selectedRole = role}) 
        }) 
      </div> 
    } 
    </div> 

    链接请求的地址是GetPeople,Ajax请求的URL则仅是GetPeopleData,请求的HTML结果作用于tablebody。

    Ajax回调

    AjaxOptions类暴露一组属性允许我们指定一个java脚本函数,在ajax请求周期中调用这些脚本函数:

    属性 jQuery事件 说明
    OnBegin beforeSend 在Ajax请求发送前调用
    OnComplete complete 请求成功时调用
    OnFailure error 请求失败时调用
    OnSuccess success 无论请求成功与否都在请求完成时调用

    结合回调函数我们可以对上面的例子进一步修改,首先修改控制器的GetPeopleData方法:

            public ActionResult GetPeopleData(string selectedRole = "All")
            {
                IEnumerable<Person> data = personData;
                if (selectedRole != "All")
                {
                    Role selected = (Role)Enum.Parse(typeof(Role), selectedRole);
                    data = personData.Where(p => p.Role == selected);
                }
                if (Request.IsAjaxRequest())
                {
                    var formattedData = data.Select(p => new
                    {
                        FirstName = p.FirstName,
                        LastName = p.LastName,
                        Role = Enum.GetName(typeof(Role), p.Role)
                    });
                    return Json(formattedData, JsonRequestBehavior.AllowGet);
                }
                else
                {
                    return PartialView(data);
                }
            } 

    我们使用Request.IsAjaxRequest判断请求是否来自于ajax,它的依据是浏览器在ajax请求时在头中会包含X-Requested-With=XMLHttpRequest。如果请求来自于ajax,控制器方法返回的是Json(data, JsonRequestBehavior.AllowGet)创建的JsonResult对象,默认JSON数据只在POST请求中发送,这里在第二个参数中指定JsonRequestBehavior.AllowGet允许在GET请求中使用JSON数据。MVC框架负责对formattedData做json封装,封装的格式由MVC尝试使用最适宜的方法确定,这里返回的JSON数据类似:

    ... 
    {"PersonId":0,"FirstName":"Adam","LastName":"Freeman", 
    "BirthDate":"/Date(62135596800000)/","HomeAddress":null,"IsApproved":false,"Role":0} 
    ... 

    视图中我们在AjaxOptions的OnSucess回调函数中处理返回的JSON数据:

    @using HelperMethods.Models
    @model string
    @{ 
        ViewBag.Title = "GetPeople";
        AjaxOptions ajaxOpts = new AjaxOptions
        {
            //UpdateTargetId = "tableBody",
            Url = Url.Action("GetPeopleData"),
            LoadingElementId = "loading",
            LoadingElementDuration = 1000,
            OnSuccess = "processData" 
        };
    }
    <script type="text/javascript">
        function processData(data) {
            var target = $("#tableBody");
            target.empty();
            for (var i = 0; i < data.length; i++) {
                var person = data[i];
                target.append("<tr><td>" + person.FirstName + "</td><td>"
                + person.LastName + "</td><td>" + person.Role + "</td></tr>");
            }
        }
    </script>
    <h2>Get People</h2>
    <div id="loading" class="load" style="display: none">
        <p>Loading Data...</p>
    </div>
    <table>
        <thead>
            <tr>
                <th>First</th>
                <th>Last</th>
                <th>Role</th>
            </tr>
        </thead>
        <tbody id="tableBody">
            @Html.Action("GetPeopleData", new { selectedRole = Model })
        </tbody>
    </table>
    @using (Ajax.BeginForm(ajaxOpts))
    { 
        <div>
            @Html.DropDownList("selectedRole", new SelectList(
    new[] { "All" }.Concat(Enum.GetNames(typeof(Role)))))
            <button type="submit">Submit</button>
        </div> 
    }
    
    <div>
        @foreach (string role in Enum.GetNames(typeof(Role)))
        { 
            <div class="ajaxLink">
                @Ajax.ActionLink(role, "GetPeople",
    new { selectedRole = role },
    new AjaxOptions
    {
        Url = Url.Action("GetPeopleData", new { selectedRole = role }),
        OnSuccess = "processData"
    })
            </div> 
        }
    </div>

    脚本函数processData在AjaxOptions的OnSuccess回调时调用,它负责处理请求返回的JSON数据,从中分拆出各个Person对象,根据这些数据直接改写tableBody标签的内容,因此我们不再需要在AjaxOptions通过UpdateTargetId指定要替换内容的元素。

    以上为对《Apress Pro ASP.NET MVC 4》第四版相关内容的总结,不详之处参见原版 http://www.apress.com/9781430242369。 

  • 相关阅读:
    AsyncTask异步加载和HttpURLConnection网络请求数据
    The Vertu of the Dyamaund钻石
    英文finaunce金融
    Middle English finaunce金融
    金融finaunce财经
    英语fraunce法兰西
    France Alternative forms Fraunce
    python关于try except的使用方法
    java实现在线预览--poi实现word、excel、ppt转html
    static 关键字有什么作用
  • 原文地址:https://www.cnblogs.com/duanshuiliu/p/3702835.html
一二三 - 开发者的网上家园