65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET MVC 中使用 AJAX 渲染局部视图和 JSON 数据

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (21投票s)

2014 年 3 月 24 日

CPOL

7分钟阅读

viewsIcon

187558

downloadIcon

4353

本文解释了如何使用 AJAX 渲染局部视图和 JSON 数据。

引言

本文解释了如何使用 AJAX 渲染局部视图和 JSON 数据。我将本文分为三个部分来理解这两个概念,第一部分描述了这两个概念中通用的基本代码和结构,第二部分描述了如何使用 AJAX 渲染局部视图,最后一部分描述了如何使用 AJAX 在网页上渲染 JSON 数据。

我将通过一个简单的例子来解释这些概念。这个例子是根据出版商在网页上显示书籍。我从下拉列表中选择一个出版商,然后书籍信息将根据该出版商显示在网页上。那么让我们详细看看这个例子。

入门

我将 ADO.NET 实体模型添加到应用程序中,以便执行从“Development”数据库映射的数据库操作。ADO.NET 实体模型是一种对象关系映射(ORM),它在 ADO.NET 组件之上创建了更高抽象的对象模型。此 ADO.NET 实体模型与“Development”数据库映射,因此上下文类是继承了 DbContext 类的“DevelopmentEntities”。

这个“Development”数据库有两个表,一个是 Publisher 表,另一个是 BOOK 表。两个表都有 1 对多关系,换句话说,一个出版商可以出版多本书,但每本书都与一个出版商相关联。如果您想了解更多关于此应用程序数据库设计的信息,请查阅我的上一篇文章使用 LINQ to SQL 的 MVC 应用程序

ADO.NET 实体模型映射到这两个表。它的连接字符串与上下文类名同名,并且此连接字符串是在 web.config 文件中创建的。您可以更改连接字符串的名称。上下文类名和连接字符串名称只是一个约定,而不是配置,因此您可以使用有意义的名称进行更改。以下图 1.1 显示了 ADO.NET 实体模型与两个表的映射。

The ADO.NET Entity Model mapping with Publisher and Book tables.

图 1.1 ADO.NET 实体模型与 Publisher 和 Book 表的映射。

现在 ADO.NET 实体模型已准备好用于应用程序,是时候进入应用程序的下一步,即模型设计,所以让我们看看应用程序的模型。

模型设计

如您所知,应用程序的目的是创建两个实体(PublisherBOOK),我已经创建了相同的实体,因此我需要创建两个模型,一个用于出版商,另一个用于书籍。

我在 Model 文件夹下创建了一个出版商模型 (Publisher.cs),它包含出版商 ID 和出版商列表,如以下代码片段所示。

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
 
namespace JsonRenderingMvcApplication.Models
{
    public class PublisherModel
    {
        public PublisherModel()
        {
            PublisherList = new List<SelectListItem>();
        }
 
        [Display(Name="Publisher")]
        public int Id { get; set; }
        public IEnumerable<SelectListItem> PublisherList { get; set; }
    }
}

在出版商模型之后,我在同一个文件夹中创建了一个书籍模型 (Book.cs)。它具有与书籍相关的基本属性。以下是书籍模型的代码片段。

namespace JsonRenderingMvcApplication.Models
{
    public class BookModel
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string Year { get; set; }
        public decimal Price { get; set; }
    }
}

现在模型已准备好使用,现在转向控制器。

控制器设计

我创建了两个控制器,一个用于出版商,在下拉列表中显示出版商列表,另一个是书籍控制器,根据出版商显示书籍详情。出版商控制器定义了一个在两个概念中相同的单一操作方法;渲染局部视图和 JSON 数据,而书籍控制器定义了两个操作方法,一个用于局部视图渲染,另一个用于 JSON 数据渲染,因此您将在本文后面看到它。

现在根据 MVC 约定在 Controllers 文件夹下创建出版商控制器 (PublisherController.cs)。此控制器有一个单一的操作方法,用于在视图上显示出版商列表。以下是出版商控制器的代码片段。

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using JsonRenderingMvcApplication.Models;
 
namespace JsonRenderingMvcApplication.Controllers
{
    public class PublisherController : Controller
    {
        public ActionResult Index()
        {
            PublisherModel model = new PublisherModel();
            using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
            {
                List<DAL.Publisher> PublisherList = context.Publishers.ToList();
                model.PublisherList = PublisherList.Select(x =>
                                        new SelectListItem()
                                        {
                                            Text = x.Name,
                                            Value = x.Id.ToString()
                                        });
                                 }
            return View(model);
        }
    }
}

现在在应用程序的 Controllers 文件夹下创建书籍控制器 (BookController.cs),并将其留空,不带任何操作方法,您将在该控制器中定义两个操作方法,一个用于局部视图渲染,另一个用于 JSON 数据渲染。现在,文章的第一部分已完成,如引言中所述,现在逐个介绍这两种方法。

渲染局部视图

进行 AJAX 请求时,返回 HTML 内容作为结果非常简单。只需使用 PartialView 方法返回一个 ActionResult,该方法将向调用 JavaScript 返回渲染的 HTML。

现在在书籍控制器中定义一个操作方法,该方法使用 PartialView 返回 ActionResult。此操作方法根据在此操作方法中作为参数传递的出版商 ID 检索书籍列表。以下是此操作方法的代码片段。

public ActionResult BookByPublisher(int id)
{
    IEnumerable<BookModel> modelList = new List<BookModel>();
    using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
    {
        var books = context.BOOKs.Where(x => x.PublisherId == id).ToList();
        modelList = books.Select(x =>
                   new BookModel()
                    {
                             Title = x.Title,
                             Author = x.Auther,
                             Year = x.Year,
                             Price = x.Price
                   });
    }
    return PartialView(modelList);  
 }

我在 RouteConfig 类 (App_Start/RouteConfig.cs) 的 RegisterRoute() 方法中为此操作定义了一个路由。

routes.MapRoute("BookByPublisher",
       "book/bookbypublisher/",
        new { controller = "Book", action = "BookByPublisher" },
        new[] { "JsonRenderingMvcApplication.Controllers" });

现在为出版商创建一个视图,该视图包含一个用于出版商的下拉列表,并使用 AJAX 根据出版商下拉列表中选择的值显示书籍详细信息。此视图是一个索引 (Views/Publisher/Index.cshtml)。以下是 Index 视图的代码片段。

@model JsonRenderingMvcApplication.Models.PublisherModel
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript"> 
   
    $(document).ready(function ()
    {
        $("#Id").change(function ()
        {
             var id = $("#Id").val();
             var booksDiv = $("#booksDiv");
             $.ajax({
                 cache: false,
                 type: "GET",
                 url: "@(Url.RouteUrl("BookByPublisher"))",
                data: { "id": id },
                success: function (data)
                {
                    booksDiv.html('');
                    booksDiv.html(data);
                },
                error: function (xhr, ajaxOptions, thrownError)
                {
                    alert('Failed to retrieve books.');                    
                }
            });
        });
    });      
</script>
<div>
    @Html.LabelFor(model=>model.Id)
    @Html.DropDownListFor(model => model.Id, Model.PublisherList)
</div>
<div id="booksDiv">
</div>

运行应用程序并从出版商下拉列表中选择一个项目。然后您将获得如图 1.2 所示的结果。

 output result using HTML rendering

图 1.2 使用 HTML 渲染的输出结果

渲染 JSON 数据

在上一节中,您已经了解到可以在 AJAX 请求上渲染 HTML,但本节中您将了解只渲染序列化数据,而不是整个 HTML。ASP.NET MVC 以 JsonResult 操作结果的形式提供本机 JSON 支持,它接受一个模型对象,该对象被序列化为 JSON 格式。为了通过 JSON 向控制器操作添加 AJAX 支持,只需使用 Controller.Json() 方法创建一个包含要序列化对象的新 JsonResult

现在,在书籍控制器中创建一个操作方法 BooksByPublisherId(),该方法返回 JsonResult。此操作方法根据在此操作方法中作为参数传递的出版商 ID 检索书籍列表。以下是此操作方法的代码片段。

public JsonResult BooksByPublisherId(int id)
{
      IEnumerable<BookModel> modelList = new List<BookModel>();
      using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
      {
            var books = context.BOOKs.Where(x => x.PublisherId == id).ToList();
            modelList = books.Select(x =>
                        new BookModel()
                        {
                                   Title = x.Title,
                                   Author = x.Auther,
                                   Year = x.Year,
                                    Price = x.Price
                           });
            }
            return Json(modelList,JsonRequestBehavior.AllowGet);
        }

创建了操作方法以返回书籍详细信息。这里 Controller.Json() 方法有两个参数,第一个用于将要序列化的数据源,第二个参数是 JsonRequestBehavior.AllowGet,它明确告知 ASP.NET MVC 框架,在响应 HTTP GET 请求时返回 JSON 数据是可以接受的。

在此案例中,JsonRequestBehavior.AllowGet 参数是必需的,因为默认情况下,ASP.NET MVC 不允许在响应 HTTP GET 请求时返回 JSON,以避免潜在的危险安全漏洞,即 JSON 劫持。

此操作方法返回的 JSON 数据如图 1.3 所示。

 JSON Data from action method

图 1.3 来自操作方法的 JSON 数据

我在 RouteConfig 类 (App_Start/RouteConfig.cs) 的 RegisterRoute() 方法中为此操作定义了一个路由。

routes.MapRoute("BooksByPublisherId",
      "book/booksbypublisherid/",
       new { controller = "Book", action = "BooksByPublisherId" },
       new[] { "JsonRenderingMvcApplication.Controllers" });

现在,修改先前创建的出版商 Index 视图,该视图包含一个用于出版商的下拉列表,并使用 AJAX 根据出版商下拉列表中选择的值显示书籍详细信息。以下是 Index 视图的代码片段

@model JsonRenderingMvcApplication.Models.PublisherModel
 
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
    $(document).ready(function () {
        $("#Id").change(function () {
            var id = $("#Id").val();
            var booksDiv = $("#booksDiv");
            $.ajax({
                cache: false,
                type: "GET",
                url: "@(Url.RouteUrl("BooksByPublisherId"))",
                data: { "id": id },
                success: function (data) {
                    var result = "";
                    booksDiv.html('');
                    $.each(data, function (id, book) {
                        result += '<b>Title : </b>' + book.Title + '<br/>' +
                                    '<b> Author :</b>' + book.Author + '<br/>' +
                                     '<b> Year :</b>' + book.Year + '<br/>' +
                                      '<b> Price :</b>' + book.Price + '<hr/>';
                    });
                    booksDiv.html(result);
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert('Failed to retrieve books.');
                }
            });
        });
    });
</script>
<div>
    @Html.LabelFor(model=>model.Id)
    @Html.DropDownListFor(model => model.Id, Model.PublisherList)
</div>
<div id="Div1">
</div>

运行应用程序并从出版商下拉列表中选择一个项目;然后您将获得如图 1.4 所示的结果。

output result using JSON data rendering

图 1.4:使用 JSON 数据渲染的输出结果

结论

哪个更快?可以说 JSON 数据渲染比局部视图渲染更快。我使用两种方法进行相同的请求,并获得以下表中所示的响应数据(以字节为单位)。

内容类型 标题 正文 总计(字节)
text/html 434 375 809
应用程序/json 398 197 595
表 1.1:响应字节摘要

当处理少量服务器数据时,这是一个很大的区别。当我使用圆形图表示这些统计数据时,它们看起来像

circle graph

© . All rights reserved.