博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET MVC4 IN ACTION学习笔记-第六波[Ajax in ASP.NET MVC][3/3]
阅读量:5236 次
发布时间:2019-06-14

本文共 11304 字,大约阅读时间需要 37 分钟。

前面阅读第六波导航:

image         原著:ASP.NET MVC 4 IN ACTION

         大家好!

         我是茗洋芳竹,首先声明,我不是一个翻译人员,我是个90后程序员.

         夏天到了,哎,人也变懒了,开始写吧…

         读者约定:

         ”网页标签 element“代表 网页上的一个DOM元素,例如 div element就是网页中有个div的DOM元素

7.3 Ajax返回JSON 和 客户端模版的使用

      前面几节都是对Ajax请求返回HTML,虽然用这种方法没有任何错误,但是你没有简化HTML的返回,其实你可以返回任意种格式的数据,例如,纯文本(plain text),XML,JSON。在下面一节我们将使用通过Ajax返回JSON的模式写程序

 

 

 

7.3.1 Ajax with JSON

        JSON全称:JavaScript Object Notation

        它提供了一种很简单的方式表达数据,如果你熟悉JavaScript Object,你就会很容易熟悉JSON。

        两种表达数据的方式的比较

       XML数据:

5
Jeremy
Skinner
/content/jeremy.jpg
Jeremy Skinner is a C#/ASP.NET software developer in the UK.

      JSON格式

          {
             "Id":5, "FirstName":"Jeremy"
             "LastName":"Skinner",
             "PictureUrl":"/content/jeremy.jpg",
            "Bio":"Jeremy Skinner is a C#/ASP.NET software developer in the UK."
           }

  

如果你熟悉C#中的集合,那你就很快会用JSON,通过键,获得对象,然后你自己再操作对象就行了,这里不多说了

为了演示JSON,我们添加一个SpeakerController,然后在Models文件夹下添加一个Speaker实体类:

1:   public class Speaker
2:      {
3:          public int Id { get; set; }
4:          public string FirstName { get; set;}
5:          public string LastName { get; set; }
6:          public string PictureUrl { get; set; }
7:          public string Bio { get; set; }
8:          public string FullName
9:          {
10:              get { return string.Format("{0} {1}", FirstName, LastName); }
11:          }
12:      }

 

再手动创建一个SpeakerRepository仓库类,因为我们没有使用到数据库,我们添加的数据都在内存里面,真实的项目都是使用数据库,这里用于演示用的。在model的构造函数中,创造一个SpeakerRepository集合,初始化数据,代码如下:

1:  using System;
2:  using System.Collections.Generic;
3:  using System.Linq;
4:  using System.Web;
5:   
6:  namespace AjaxExamples.Models
7:  {
8:      public class SpeakerRepository
9:      {
10:          private static readonly List
_speakers = new List
();
11:   
12:          static SpeakerRepository()
13:          {
14:              _speakers = new List
{
15:   
16:                 new Speaker
17:                  {
18:                      Id = 1,
19:                      FirstName = "Jimmy",
20:                      LastName = "Bogard",
21:                      PictureUrl = "/content/jimmy.png",
22:                      Bio = "Jimmy is a Principal Consultant at Headspring Systems in Austin, TX.",
23:                  },
24:                  new Speaker
25:                  {
26:                      Id = 2,
27:                      FirstName = "Jeffrey",
28:                      LastName = "Palermo",
29:                      PictureUrl = "/content/jeffrey.jpg",
30:                      Bio = "Jeffrey Palermo is a Microsoft MVP and Chief Technology Officer of Headspring Systems in Austin, TX.",
31:                  },
32:                  new Speaker
33:                  {
34:                      Id = 3,
35:                      FirstName = "Eric",
36:                      LastName = "Hexter",
37:                      PictureUrl = "/content/eric.jpg",
38:                      Bio = "Eric Hexter is an Enterprise Architect at Dell in Austin, TX.",
39:                  },
40:                  new Speaker
41:                  {
42:                     Id = 4,
43:                     FirstName = "Matt",
44:                     LastName = "Hinze",
45:                     PictureUrl = "/content/matt.jpg",
46:                     Bio = "Matt Hinze is a Principal Consultant at Headspring Systems in Austin, TX.",
47:                  },
48:   
49:                 new Speaker
50:                  {
51:                      Id = 5,
52:                      FirstName = "Jeremy",
53:                      LastName = "Skinner",
54:                      PictureUrl = "/content/jeremy.jpg",
55:                      Bio = "Jeremy Skinner is a C#/ASP.NET software developer in the UK.",
56:                  }
57:              };
58:   
59:   
60:          }
61:   
62:   
63:   
64:      }
65:  }

我们再在这里面写几个获得数据的方法

1:      public IEnumerable
FindAll()
2:          {
3:              return _speakers;
4:          }
5:   
6:          public Speaker FindSpeaker(int id)
7:          {
8:              return _speakers.SingleOrDefault(x => x.Id == id);
9:          }

最后我们处理那个SpeakerController

在Index action中添加如下代码,返回所有的Speaker信息,添加对应的Index view

1:    private readonly SpeakerRepository _repository = new SpeakerRepository();
2:   
3:          public ActionResult Index()
4:          {
5:              var speakers = _repository.FindAll();
6:              return View(speakers);
7:          }

这个方法,用于首页显示Speaker信息,然后单击一项,我们要显示详情,那么我们添加一个Details action,参数为id

代码如下:

1:   public ActionResult Details(int id)
2:     {
3:              var speaker = _repository.FindSpeaker(id);
4:              return Json(speaker, JsonRequestBehavior.AllowGet);
5:      }

看的话,估计你也懂了,但是我还是要讲一下JSON方法,更深入一下,比如为什么后面加了个参数,其实可以不要的

 

 

这里,我们使用了Id从仓库里获得 Speaker的信息,通过Controller的JSON方法可以将一个对象序列化成JSON。这个方法返回一个JSONResult,JSONResult是实现ActionResult的,当开始把一个对象序列化成一个JSON的时候,它会把结果写入 result stream(结果流)里面,就可以返回信息了。

         ASP.NET MVC,JSON和GET请求

         你也注意到了,在上面的代码,Controller中的JSON方法的参数,我们使用了一个枚举值JsonRequestBehavior.AllowGet。默认的JsonResult都是以Post方式响应,如果你想以Get方式,就这样用这个行为。

在这里用这个行为可以避免 JSON hijacking(劫持,是一种跨站点的脚本的form)

         如果一个站点去响应Get请求,返回的JSON数据含有敏感数据,那么一个恶意的网站就可以在一个敏感的位置(容易攻击的位置,适合坏人下手的位置)通过嵌入脚本可以潜在地让不知情的用户看到他们(坏人)的数据。

         如果一个认证了的用户访问了这个恶网站,这些数据就会被下载,然后恶意的网站就可以得到它,我们将会在下一波讲 JSON hihacking

在我们的特殊的例子中,我们不会返回敏感的数据,所以让JSON以GET请求访问绝对安全。

接下来我们看下Index view,要使用到的一些图片下载,    下载好后,放到Content文件夹下(css文件提供,因为主要讲MVC)

我们先建立一个空的Speakers.js,用于写js代码

关于Index view代码如下:

1:  @model IEnumerable
2:  @{
3:      ViewBag.Title = "JSON Example";
4:  }
5:  @section head {
6:      
7:      
8:  }
9:   
10:  

Speakers

11:   
12:  
    13:      @foreach (var speaker in Model) {
    14:      
  • 15:          @Html.ActionLink(speaker.FullName, "Details", new { id = speaker.Id })
    16:      
    17:      }
    18:  
    19:   
    20:  
    21:   
    22:  
    23:  

    我们后台传过来一个list,视图中标记了Model,使得视图变成一个强类型视图,我们使用foreach循环,显示展示结果,每个结果添加超链接,单击显示详情。

    我们使用一个div element,显示单击后的详情信息,我们现在不使用,我们将在7.3.2中使用

    接下来我们在Speakers.js文件中写入Js

    1:  $(document).ready(function () {
    2:      $("ul.speakers a").click(function (e) {
    3:          e.preventDefault();
    4:          $("#indicator").show();
    5:          var url = $(this).attr('href');
    6:          $.getJSON(url, null, function (speaker) {
    7:              $("#indicator").hide();
    8:              alert(speaker.FirstName);
    9:          });
    10:      });
    11:  });

    $.getJSON方法具体参考 Jquery手册,如果你使用过jquery,这点绝对不是问题

    getJSON方法会自动将JSON string转换成JavaScript对象。

    运行项目,效果图:

     

    光显示一个 FirstName是没有用的,接下来我们在页面中添加更多的标签,来显示说话者的详细信息,还有照片。

    下面我们讲客户端模版。

     

    7.3.2 Client-side templates

             我们在服务端大多都是使用Razor文件作为模版,我们也可以在客户端创建一个模版

             客户端模版 允许我们不需要返回服务器或者通过JavaScript构建elements就可以立即在浏览器中立即生成markup(标签,网页中的元素),我们有几种客户端模版库可供我们选择,但是我们使用jQuery-tmpl 一个jQuery写的模版库,微软写的,已经贡献到jQuery 项目,开源。

    我们修改speaker列表,让speaker name可以click,然后他们的bio(个人简历)和照片将会显示:

    为了引用jQuery-tmpl,我们可以从 下载,然后把他们放到我们项目的scripts文件夹里面。或者我们可以直接引用来自   Microsoft’s  CDN  的 ,一旦引用好了,我们就可以在view中添加 模版了

    点击直接下载      注意,这个tmpl.js文件一定要放在 Speakers.js上面,注意加载顺序

     

    1:  
    2:  
    3:      
    4:          alt="Speaker image" class="speaker-pic" />
    5:      

    6:          ${Bio}
    7:      

    8:   
    9:   
    10:  

     

    这里我们引用了 jQuery-tmpl脚本,然后生命了一个模版,模版在一个script element中,用的是type=”text/x-jquery-tmpl”,把template的标签放到一个script element中可以保证,页面载入时,不会直接显示模版。

    我们的模版包括了照片和个人简历的信息,我们引用JSON对象,通过使用${}代码块(nuget)来包裹(wrap)它们,这些在模版呈现的时候,会被替换的。下面我们需要修改Speakers.js中的JavaScript来呈现这个模版。

    修改的代码如下:

    1:  $(document).ready(function () {
    2:      $("ul.speakers a").click(function (e) {
    3:          e.preventDefault();
    4:   
    5:          $(".selected-speaker").hide().html('');
    6:          $("#indicator").show();
    7:   
    8:          var url = $(this).attr('href');
    9:   
    10:          $.getJSON(url, null, function (speaker) {
    11:              $("#indicator").hide();
    12:   
    13:              $("#speakerTemplate")
    14:                  .tmpl(speaker)
    15:                  .appendTo('.selected-speaker');
    16:   
    17:              $('.selected-speaker').show();
    18:          });
    19:      });
    20:  });

    这里代码只有一点点不同,第5行,每次查看详情的时候,先清空原来的数据

    第13行,模版的位置 点 tmpl(JSON转换过的JavaScript对象)点 appendTo(在哪里显示)

     

     

    7.3.3 完成 这个例子

           这个例子已经大大地完成了,但是还有个缺点。如果JavaScript禁用了,单击的时候,JSON就作为文件下载了,而不是呈现一个模版。

           为了完成这个,我们可以一个最简单的方法,修改SpeakersController中的 Details action

    1:   public ActionResult Details(int id)
    2:          {
    3:              var speaker = _repository.FindSpeaker(id);
    4:              if (Request.IsAjaxRequest()) {
    5:                  return Json(speaker, JsonRequestBehavior.AllowGet);
    6:              }
    7:              return View(speaker);
    8:          }

    除了依靠在我们的代码中使用if,我们还可以使用一个action method selector,用于Ajax和non-Ajax请求。在第一波我们已经看到了 action selector怎么使用的了,我们可以创建一个继承ActionMethodSelector的AcceptAjaxAttribute

    我们在Filters文件下建立

    代码如下:

    1:  using System;
    2:  using System.Reflection;
    3:  using System.Web.Mvc;
    4:   
    5:  namespace AjaxExamples.Filters
    6:  {
    7:      [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    8:      public class AcceptAjaxAttribute : ActionMethodSelectorAttribute
    9:      {
    10:          public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    11:          {
    12:              return controllerContext.HttpContext.Request.IsAjaxRequest();
    13:          }
    14:      }
    15:  }

    如果当前的请求是通过Ajax请求的,IsValidForRequest方法就会返回true

    现在我们在SpeakersController中使用这个attribute,通过定义两个action-----一个是Ajax请求,另一个是正常的请求

    1:     public ActionResult Details(int id)
    2:          {
    3:              var speaker = _repository.FindSpeaker(id);
    4:              if (Request.IsAjaxRequest()) {
    5:                  return Json(speaker, JsonRequestBehavior.AllowGet);
    6:              }
    7:              return View(speaker);
    8:          }
    9:   
    10:          [ActionName("Details")]
    11:          public ActionResult Details_NonAjax(int id)
    12:          {
    13:              var speaker = _repository.FindSpeaker(id);
    14:              return View(speaker);
    15:          }

    第一个重载的Details action被我们创建的AcceptAjaxAttribute注解(annotated)了。这个保证了这个方法只能被Ajax方法请求到,这个版本的action会返回JSON序列化后的speaker数据。

    另一个重载的没有使用AcceptAjaxAttribute,这就意味着它将可以被非Ajax请求访问,这个action简单的传递了个speaker实例对象给视图,注意,C#中不能定义同名字的相同签名的两个方法,这第二个版本的action被命名为Details_NonAjax,但是他依然可以被URL/Speakers/Details访问,因为它被ActionName注解了。

    这个AcceptAjaxAttribute作为ASP.NET MVC Futures DLL的一部分可以被找到,您可以通过

    在这个特殊的例子中,使用AcceptAjaxAttribute不会带来太多的方便,但是在一个action 表单Ajax和非Ajax处理的操作是不一样的情形的时候,把处理的代码分开写,会具有可读性。

    我们也可以定义一个视图,针对非Ajax版本的action。这个视图显示speaker的详细信息,很多跟客户端模版一样

    我们添加 Details_NonAjax对应的视图;

    1:  @model AjaxExamples.Models.Speaker
    2:   
    3:  @section head {
    4:      
    5:  }
    6:  

    Speaker Details: @Model.FullName

    7:   
    8:  

    9:      
    10:                    alt="@Model.FullName" />
    11:      @Model.Bio
    12:  

    13:   
    14:  
    15:  @Html.ActionLink("Back to speakers", "index")

     

    Details中的代码如下:

    1:  @model AjaxExamples.Models.Speaker
    2:  @{
    3:      ViewBag.Title = "Speaker Details";
    4:  }
    5:  @section head {
    6:      
    7:      
    8:          .speaker img
    9:          {
    10:              float: left;
    11:              margin: 5px;
    12:          }
    13:
    14:      
    15:  }
    16:   
    17:  

    Speaker Details: @Model.FullName

    18:   
    19:  

    20:      @Model.FullName
    21:      

    @Model.Bio

    22:  

    23:   
    24:  
    25:  @Html.ActionLink("Back to speakers", "index")

     

    我们注释掉 Views/Shared/_Layout.cshtml中底部的一行jquery代码

    在顶部重新引用 一个jquery库

     

    运行项目,效果如下:

     

     代码下载:http://download.csdn.net/download/yangyanghaoran/5393947

     

     

    转载于:https://www.cnblogs.com/AaronYang/archive/2013/05/17/3083082.html

    你可能感兴趣的文章
    纪念日倒计时程序
    查看>>
    Python读取PDF文档
    查看>>
    leetcode-Game of Life-289
    查看>>
    (转)浅谈移动操作系统的跨应用通信机制
    查看>>
    常用的Hql语句
    查看>>
    可变字符串
    查看>>
    Postman
    查看>>
    事件的故事说明
    查看>>
    超大型 LED 显示屏
    查看>>
    poj 2342 Anniversary party_经典树状dp
    查看>>
    以后再也不写英文的文章了
    查看>>
    JS常用
    查看>>
    c# 怎么动态修改webservice的地址和端口 动态修改配置文
    查看>>
    usaco-5.1-theme-passed
    查看>>
    Android程序对不同手机屏幕分辨率自适应的总结
    查看>>
    分治法
    查看>>
    java并发值多线程同步业务场景以及解决方案
    查看>>
    Android开发——LinearLayout和RelativeLayout的性能对比
    查看>>
    URL传递中文参数,大坑一枚,Windows与Linux效果竟然不一致(两种解决方法)
    查看>>
    百度UEditor上传图片-再总结一次
    查看>>