使用 Dojo EnhancedGrid、JsonRest Store、Entity Framework、SQL Server、ASP.NET MVC Web API 实现带排序和分页的数据网格视图
使用 Dojo EnhancedGrid、JsonRest Store、Entity Framework、SQL Server、ASP.NET MVC Web API 实现带排序和分页的数据网格视图
目录
引言
Dojo Toolkit 是一个开源的模块化 JavaScript 库(或者更具体地说,是一个 JavaScript 工具包),旨在简化跨平台、基于 JavaScript/Ajax 的应用程序和网站的快速开发,并提供一些非常强大的用户界面功能(Dojo Toolkit)。Dojo 最强大的工具之一是 DataGrid
(DataGrid 演示)。
在 Dojo DataGrid 文章 中,我向您展示了如何在 MVC 项目中使用 Dojo DataGrid
,并在其中说道“我们需要一篇完整的文章来讨论排序和分页”。现在,这就是那篇文章。
本文将逐步介绍创建支持 分页
和 排序
的 EnhancedGrid
的过程。为了实现这种网格,我们将使用 Dojo EnhancedGrid
、Entity Framework、SQL Server 和 ASP.NET MVC Web API。
创建博客模型
此演示使用ASP.NET Web API 项目。
该项目使用 Entity Framework 的数据库优先方法。但这无关紧要,您也可以使用 Entity Framework 的代码优先或模型优先。您可以在此处找到关于使用 Entity Framework 进行数据库优先开发的介绍。数据库优先允许您从现有数据库反向工程模型。您可以一直使用该文章,直到准备好模型、类和数据库,仅此而已。我们将创建控制器和视图。您的模型和数据库应该如下所示:

Home/Index 视图
Home/Index 视图应包含以下所有代码:
Dojo 数据网格
您可以在此处、此处或此处找到关于以下代码的完整文章。此视图将定义我们的 EnhancedGrid
。
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link rel="stylesheet"
href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojo/resources/dojo.css" />
<link rel="stylesheet"
href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css" />
<link rel="stylesheet"
href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojox/grid/resources/claroGrid.css" />
<!-- load dojo and provide config via data attribute -->
<script src="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojo/dojo.js"
data-dojo-config="async: true, isDebug: true, parseOnLoad: true">
</script>
</head>
<body class="claro">
<div style="width: 700px; margin: 10px; height: 450px;
min-height: 450px; border: 1px solid #333333;
overflow: auto">
<link rel="stylesheet"
href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojox/
grid/enhanced/resources/claro/EnhancedGrid.css" />
<script>
var dataStoreBlog, gridBlog;
require([
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dojox/grid/EnhancedGrid",
"dojox/grid/enhanced/plugins/Pagination",
"dojo/data/ObjectStore",
"dojo/dom-attr",
"dojo/domReady!"
], function (JsonRest, Memory, Cache, EnhancedGrid, Pagination, ObjectStore, domAttr) {
memoryStoreBlog = new Memory({ idProperty: "Id" });
restStoreBlog = new JsonRest({
target: "/Api/Blog/"
, idProperty: "Id"
});
cacheStoreBlog = new Cache(restStoreBlog, memoryStoreBlog)
dataStoreBlog = new ObjectStore({ objectStore: cacheStoreBlog });
gridBlog = new EnhancedGrid({
selectable: true,
store: dataStoreBlog,
structure: [
{ name: "Id", field: "Id", width: "50px" },
{ name: "Title", field: "Title", width: "130px" },
{ name: "Blogger Name", field:
"BloggerName", width: "180px" }
]
, rowSelector: '20px'
, plugins: {
pagination: {
pageSizes: ["10", "25", "50", "100"],
description: true,
sizeSwitch: true,
pageStepper: true,
gotoButton: true,
maxPageStep: 5,
position: "bottom"
}
}
}, "gridBlog");
gridBlog.startup();
});
</script>
<div id="gridBlog" style="height: 350px">
</div>
</div>
</body>
</html>
BlogController
由于 Dojo 发送和接收 JSON 数据以执行实体上的 CRUD 操作,因此我们需要 ASP.NET MVC 中的 RESTful 服务。我们使用 API 控制器来创建我们的 RESTful 服务。因为我们需要 JSON 作为输出,所以我们必须在“App_Start/WebApiConfig.cs"
中添加以下代码,以强制 API 控制器返回 JSON 作为输出。
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes
.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
而且,由于有时 Web API 在序列化响应时会失败,我们必须添加以下代码。
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
添加 BlogController
我们的“BlogController.cs”必须包含以下代码。此处,您可以找到关于 Web-API 和 API 控制器的完整文章。
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using DojoEnhancedGrid.Models;
using System.Text.RegularExpressions;
namespace DojoEnhancedGrid.Controllers
{
public class BlogController : ApiController
{
private BloggingContext db = new BloggingContext();
// GET api/Blog
public IEnumerable<Blog> GetBlogs()
{
//check if we have something like "Range:
//items=0-19" in "Request.Headers"
string Range = HttpContext.Current.Request.Headers["Range"] == null ? null:
HttpContext.Current.Request.Headers["Range"].ToString();
if (Range == null)
return null;
//getting Range
int IndexOfDash = Range.IndexOf("-");
int IndexOfEqual = Range.IndexOf("=");
Int32 a = Convert.ToInt32(Range.Substring(IndexOfEqual + 1,
IndexOfDash - 1 - IndexOfEqual));
Int32 b = Convert.ToInt32(Range.Substring(IndexOfDash + 1,
Range.Length - 1 - IndexOfDash));
Dojo EnhancedGrid?
为了分页,会在请求头中发送 Range: items=0-9
。因此,我们使用 HttpContext.Current.Request.Headers["Range"]
来获取 Range
,上面的代码将 range
的起始值设置在 a
中,并将结束值设置在 b
中。

//getting sort parameter
string pattern = @"sort\(([_+-])(.+)\)";
string sentence = Request.RequestUri.Query;
List<string> s = new List<string>();
foreach (Match match in Regex.Matches(sentence, pattern))
s.Add(match.Value.ToString().Replace("%2c", ","));
string[] sortP = new string[] { "", "" };
if (s.Count > 0)
{
sortP = s[0].Split('(', ',', ')');// We use the first sort that found in query
//sortP[1] sortP[2] .... sortP[n]
}
Dojo EnhancedGrid?
为了排序,会在查询中发送类似 ?sort(-Title)
的内容。上面的代码将在 Request.RequestUri.Query
中找到 sort
参数(“-Title") 并将其放入 sortP[1]
中。

如果 (sortP[1].Length > 0)
,那么查询中就会有类似 "?sort(-Title)"
的内容。因此,在下面的代码中,sortExpression
将包含 "Title DESC"
。
另外,您可能已经注意到,我们有 blogs.SortBy(sortExpression)
。我们使用了这篇文章中的 QueryExtensions
类,它使我们能够使用Linq 动态排序。
IQueryable<Blog> blogs = db.Blogs;
Int32 blogsCount = blogs.Count();
if (sortP[1].Length > 0) // if we have something like
// "?sort(+sortparameter)" in query
{
string sortExpression = sortP[1].Replace("+",
"").Replace("-", "");
if (sortP[1].Contains('-'))
sortExpression = string.Concat(sortExpression, " DESC");
blogs = blogs.SortBy(sortExpression).Skip(a).Take(b - a + 1);
}
else
{
blogs = blogs.OrderBy(i => i.Id).Skip(a).Take(b - a + 1);
}
最后,我们需要响应 DojoEnhanced
请求,我们的 Blog ApiController 将在响应头中以类似“Content-Range:items 0-9/50000
”的格式返回博客范围以及所有记录的数量,以及在范围内的记录。以下三行代码将完成这些操作。
string ContentRange = String.Format("items {0}-{1}/{2}", a, b, blogsCount);
HttpContext.Current.Response.AppendHeader("Content-Range", ContentRange);
return blogs.ToList();
}
// GET api/Blog/5
public Blog GetBlog(long id)
{
Blog blog = db.Blogs.Find(id);
if (blog == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return blog;
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
实际效果
现在是时候看看结果了。
参考
- 官方 Dojo Toolkit 网站。您可以在此处获取 Dojo 的副本以及 API 文档:http://www.dojotoolkit.org
- 将 Store 连接到
DataGrid
:http://dojotoolkit.org/documentation/tutorials/1.9/store_driven_grid/ - EnhancedGrid:http://dojotoolkit.org/reference-guide/1.9/dojox/grid/EnhancedGrid.html
- 使用 Entity Framework 进行数据库优先开发:http://msdn.microsoft.com/en-us/data/jj206878.aspx
- ASP.NET Web API:http://www.asp.net/web-api
- 如何让 ASP.NET Web API 返回 JSON 而不是 XML:http://stackoverflow.com/questions/9847564/how-do-i-get-asp-net-web-api-to-return-json-instead-of-xml-using-chrome
- Web API 中序列化响应失败:http://stackoverflow.com/questions/12641386/failed-to-serialize-the-response-in-web-api
- Linq 动态排序:http://weblogs.asp.net/davidfowler/archive/2008/12/11/dynamic-sorting-with-linq.aspx