ASP.NET MVC Flexigrid 示例






4.75/5 (38投票s)
如何使用 LINQ to SQL、用于 JQuery 的 Flexigrid 和 JSON 创建一个 ASP.NET MVC 示例。
引言
本文将分步演示如何使用 Microsoft 新的 ASP.NET MVC 框架和 Flexigrid 创建一个基本演示应用程序。为使此演示保持简单,我们将不介绍单元测试、输入验证、错误处理、数据封装、身份验证、路由或完善的 MVC 应用程序的任何其他方面。
必备组件
在本文发布时,ASP.NET MVC 已发布第一个 Beta 版本。为了使 ASP.NET MVC 和 LINQ to SQL 正常工作,您需要确保已安装 VS2008 SP1 和 .NET 3.5 SP1。重要提示:有几个预发布产品(如Microsoft Silverlight Tools Beta 1)将阻止 VS2008 SP1 成功安装。因此,在安装 VS2008 SP1 之前,应运行VS2008 Service Pack Preparation Tool。
- Visual Studio 2008 Service Pack Preparation Tool[^]
- Microsoft Visual Studio 2008 Service Pack 1 [^]
- ASP.NET MVC Beta[^]
- Flexigrid 2.0 (for JQuery)[^]
创建新项目
第一步是创建一个新的 ASP.NET MVC Web Application 项目。
在本示例中,我们不介绍单元测试,因此在“Create Unit Test Project”对话框中选择“No”。
现在已经创建了一个骨架项目,我们可以进行一些清理。让我们删除一些本次示例中不会用到的项。
- 请删除AccountController.cs、Views 下的Account文件夹、About.aspx和LoginUserControl.ascx。
- 打开Index.aspx,删除
asp:Content
标签内的标记。 - 打开Site.Master,将标题和正文内容更改为以下内容
<title></title>
<body>
<div class="page">
<div id="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
</div>
</body>
About
方法,并删除Index
方法中的所有内容,除了return View();
。清理完成后,项目应如下所示
现在调试应用程序,确保一切正常运行。
添加数据库
接下来,将Northwind.mdf和Northwind_log.ldf的一个副本放在App_Data文件夹中。在 VS 中右键单击App_Data文件夹,选择“Add Existing Item”,找到Northwind.mdf文件,然后单击“OK”。执行此操作时,VS2008 会自动更新web.config文件,其中包含一个名为NorthwindConnectionString的数据库连接字符串。
现在,让我们使用 LINQ to SQL 创建一个数据访问层。在 VS 中右键单击Models文件夹,选择“Add New Item”,然后创建一个名为Customer
的 LINQ to SQL 类,然后单击“Add”。
LINQ to SQL
双击Northwind.mdf文件打开对象关系设计器。找到Customers表并将其拖到设计器页面以创建数据访问层。单击“Save”,然后重新打开“Solution Explorer”,您现在应该在Models文件夹中看到一个Customer.dbml文件。此文件包含用于访问数据库的数据上下文,它由 LINQ to SQL 自动生成。对于 Customer 数据类,数据上下文将称为CustomerDataContext
。我们需要在访问CustomerDataContext
类之前添加一个using Flexigrid.Models
。
现在运行应用程序,确保一切正常运行。
Flexigrid 和 JSON
接下来,我们将创建一个控制器方法,用于从数据库检索客户数据并将其作为 JSON 对象返回给 Flexigrid。右键单击Controllers文件夹,选择“Add New Item”,然后创建一个名为JsonController.cs的新 MVC Controller 类。
现在,我们需要编写代码来查询数据库中的 Customer 记录,并返回一个数据类,该类在序列化为 JSON 时将是 Flexigrid 可以使用的正确格式。Flexigrid 可以同时支持分页和排序,这两者都由服务器端处理。Flixgird 所期望的 JSON 格式如下
{
page: 1, // start at the first 'page' of records
total: 15, // 'total' number of records returned in the 'rows' field
rows: [
// 'id' contains the row identifier
// followed by an array of strings (one for each column) named 'cell'
{id: 3879, cell: ["", "", "", ""]},
]
}
这是Customer表的前两条记录的样子。请注意,为了便于阅读,数据已略微截断(, ... ,)。
{
"page": 1,
"total": 2,
"rows":[
{"id": "ALFKI", "cell": ["ALFKI","Alfreds Futterkiste",
"Maria Anders", ... ,"030-0076545"]},
{"id": "ANATR", "cell": ["ANATR","Ana Trujillo Emparedados y helados",
"Ana Trujillo","Owner", ... ,"(5) 555-3745"]}
]
}
向项目中添加一个名为FlexigridObject
的新类,并包含以下代码。序列化为 JSON 时,属性名将成为键名。在Customer表中,主键类型是nchar(5)
,因此我们将使用字符串来存储行 ID。
public class FlexigridRow
{
public string id;
public List<string> cell = new List<string> ();
}
public class FlexigridObject
{
public int page;
public int total;
public List<FlexigridRow> rows = new List<FlexigridRow> ();
}
现在,让我们打开JsonController.cs文件并添加以下两个方法。CustomerList()
将从Customers表中检索客户的完整列表,然后使用结果填充FlexigridObject
。在GetPropertyList
方法中,我们使用反射来迭代Customer
属性,将每个属性值添加到List
。请务必处理值为null
的情况,方法是返回一个空字符串。
using Flexigrid.Models;
public ActionResult CustomersList ()
{
var db = new CustomerDataContext ();
var q = from c in db.Customers
select c;
List<Customer> customers = q.ToList ();
FlexigridObject flexigridObject = new FlexigridObject ();
flexigridObject.page = 1;
flexigridObject.total = db.Customers.Count ();
foreach (Customer customer in customers)
{
FlexigridRow row = new FlexigridRow ()
{
id = customer.CustomerID,
cell = GetPropertyList (customer)
};
flexigridObject.rows.Add (row);
}
return View ("FlexigridObject", flexigridObject);
}
private List<string> GetPropertyList (object obj)
{
List<string> propertyList = new List<string> ();
Type type = obj.GetType ();
PropertyInfo[] properties = type.GetProperties (BindingFlags.Instance |
BindingFlags.Public);
foreach (PropertyInfo property in properties)
{
object o = property.GetValue (obj, null);
propertyList.Add (o == null ? "" : o.ToString ());
}
return propertyList;
}
添加视图
即使我们还没有添加视图,我们也应该先编译并运行代码,然后导航到我们刚刚添加的CustomersList
操作(例如:https://:1526/Json/CustomersList)。我们应该会收到以下错误
The view 'FlexigridObject' or its master could not be found.
The following locations were searched:
~/Views/json/FlexigridObject.aspx
~/Views/json/FlexigridObject.ascx
~/Views/Shared/FlexigridObject.aspx
~/Views/Shared/FlexigridObject.ascx
这告诉我们 ASP.NET MVC 中的默认路由逻辑期望在Views文件夹中找到一个名为“FlexigridObject
”的视图页面(.aspx)或视图控件(.ascx)。由于我们只需要输出 JSON 结果,因此一个简单的视图控件就足够了。让我们在Views下创建一个名为json的子文件夹,并添加一个名为FlexigridObject.ascx的新 ASP.NET MVC View User Control。
现在,我们需要为视图用户控件数据模型设置数据类型。打开FlexigridObject.ascx.cs并将类修改为以下内容
public partial class FlexigridObject : ViewUserControl <Flexigrid.FlexigridObject>
LINQ to SQL
接下来,我们需要添加一个方法来将FlexigridObject
序列化为 JSON 结果。添加一个名为JsonSerializer.cs的新类,并包含以下代码
public class JsonSerializer
{
public static string ToJsonObject (object obj)
{
DataContractJsonSerializer serializer =
new DataContractJsonSerializer (obj.GetType ());
using (MemoryStream ms = new MemoryStream ())
{
serializer.WriteObject (ms, obj);
StringBuilder sb = new StringBuilder ();
sb.Append (Encoding.Default.GetString (ms.ToArray ()));
return sb.ToString ();
}
}
}
为了使用 JSON 序列化类,我们需要向项目中添加以下引用
System.Runtime.Serialization
System.ServiceModel
System.ServiceModel.Web
现在,我们可以转到 Flexigrid 视图用户控件(FlexigridObject.ascx)并添加以下行
<%= Flexigrid.JsonSerializer.ToJsonObject (ViewData.Model) %>
让我们编译并运行代码,然后导航到CustomerList
操作(例如:https://:1526/Json/CustomersList)。哇!如果一切顺利,您应该会看到一个巨大的数据块,其中包含Customers表的所有行,并格式化为 Flexigrid JSON 对象。现在,我们有了一个可以提供给 Flexigrid 表的 URL。
完成视图
我们快完成了。我们需要将 Flexigrid 库添加到我们的项目中。首先,下载Flexigrid并将 zip 文件解压到Contents文件夹。我们仍然需要将文件添加到我们的解决方案中,因此打开 Windows Explorer 并导航到Contents文件夹。现在,将flexigrid文件夹从 Windows Explorer 拖放到 VS2008 的Contents文件夹上。您应该看到以下结果
打开Site.Master并在页眉中添加以下行。注意:jquery.js的包含必须在flexigrid.js之前,否则会收到 JavaScript 错误。
<script src="../../Content/flexigrid/lib/jquery/jquery.js" type="text/javascript"></script>
<script src="../../Content/flexigrid/flexigrid.js" type="text/javascript"></script>
<link href="../../Content/flexigrid/css/flexigrid/flexigrid.css"
rel="stylesheet" type="text/css" />
接下来,打开Index.aspx页面并添加以下代码
<div>
<table id="customers" style="display:none"></table>
<script type="text/javascript">
$("#customers").flexigrid({
url: '/Json/CustomersList',
dataType: 'json',
colModel: [
{display: 'ID', name: 'CustomerID', width: 40,
sortable: true, align: 'left'},
{display: 'Company', name: 'CompanyName', width: 100,
sortable: true, align: 'left'},
{display: 'Name', name: 'ContactName', width: 100,
sortable: true, align: 'left'},
{display: 'Title', name: 'ContactTitle', width: 100,
sortable: true, align: 'left'},
{display: 'Address', name: 'Address', width: 100,
sortable: true, align: 'left'},
{display: 'City', name: 'City', width: 80,
sortable: true, align: 'left'},
{display: 'Region', name: 'Region', width: 60,
sortable: true, align: 'left'},
{display: 'Postal Code', name: 'Postalcode', width: 80,
sortable: true, align: 'left'},
{display: 'Country', name: 'Country', width: 80,
sortable: true, align: 'left'},
{display: 'Phone', name: 'Phone', width: 80,
sortable: true, align: 'left'},
{display: 'Fax', name: 'Fax', width: 80,
sortable: true, align: 'left'}
],
searchitems: [
{display: 'Company', name: 'CompanyName'},
{display: 'Name', name: 'ContactName'},
{display: 'Title', name: 'ContactTitle'},
{display: 'Address', name: 'Address'},
{display: 'City', name: 'City'},
{display: 'Country', name: 'Country'}
],
sortname: 'CustomerID',
sortorder: 'asc',
usepager: true,
title: 'Customers',
useRp: true,
rp: 15,
showTableToggleBtn: true,
width: 1040,
height: 380
});
</script>
</div>
如果一切顺利且您没有输入任何错误,您应该会看到一个包含Northwind.Cusotmers表中所有记录的 Flexigrid。但是,您可能会注意到,Flexigrid 的控件功能(如列排序、搜索或分页)目前不起作用。为此,我们将需要调用 LINQ 的神秘魔力。
LINQ 及其他
在 Flexigrid 中,所有排序、搜索和分页都由服务器端完成。Flexigrid 将以下表单变量传递给我们的控制器
page
- 启用分页时,表示 Flexigrid 请求的页码。rp
- 启用分页时,表示每页的结果数。qtype
- 执行关键字搜索时,用于搜索的列名。query
- 在执行搜索时包含要使用的关键字sortname
- 要排序的列名。sortorder
- 升序或降序。
我们需要使用上述表单变量来修改我们的 select 查询,以返回记录的子集。向 JSON 控制器添加另一个操作处理程序,称为FlexigridList
。
public ActionResult FlexigridList ()
{
int page = int.Parse (Request.Form["page"]);
int rp = int.Parse (Request.Form["rp"]);
string qtype = Request.Form["qtype"].ToString ();
string query = Request.Form["query"].ToString ();
string sortname = Request.Form["sortname"].ToString ();
string sortorder = Request.Form["sortorder"].ToString ();
var q = from c in db.Customers
select c;
if (!string.IsNullOrEmpty (qtype) && !string.IsNullOrEmpty (query))
{
q = q.Like(qtype, query);
}
q = q.Skip ((page - 1) * rp).Take (rp);
if (!string.IsNullOrEmpty (sortname) && !string.IsNullOrEmpty (sortorder))
{
q = q.OrderBy (sortname, (sortorder == "asc"));
}
List<Customer> customers = q.ToList ();
FlexigridObject flexigridObject = new FlexigridObject ();
flexigridObject.page = page;
flexigridObject.total = db.Customers.Count ();
foreach (Customer customer in customers)
{
FlexigridRow row = new FlexigridRow ()
{
id = customer.CustomerID,
cell = GetPropertyList (customer)
};
flexigridObject.rows.Add (row);
}
return View ("FlexigridObject", flexigridObject);
}
为了支持排序和搜索,我们可以通过以下两个扩展方法来扩展 LINQ
public static class ExtensionMethods
{
public static IQueryable<T> OrderBy<T> (
this IQueryable<T> source, string propertyName, bool asc)
{
var type = typeof (T);
string methodName = asc ? "OrderBy" : "OrderByDescending";
var property = type.GetProperty (propertyName);
var parameter = Expression.Parameter (type, "p");
var propertyAccess = Expression.MakeMemberAccess (parameter, property);
var orderByExp = Expression.Lambda (propertyAccess, parameter);
MethodCallExpression resultExp = Expression.Call (typeof (Queryable), methodName,
new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote (orderByExp));
return source.Provider.CreateQuery <T> (resultExp);
}
public static IQueryable<T> Like<T> (this IQueryable<T> source,
string propertyName, string keyword)
{
var type = typeof (T);
var property = type.GetProperty (propertyName);
var parameter = Expression.Parameter (type, "p");
var propertyAccess = Expression.MakeMemberAccess (parameter, property);
var constant = Expression.Constant ("%" + keyword + "%");
var like = typeof(SqlMethods).GetMethod ("Like",
new Type[] {typeof (string), typeof (string)});
MethodCallExpression methodExp =
Expression.Call (null, like, propertyAccess, constant);
Expression<Func<T, bool>> lambda =
Expression.Lambda<Func<T, bool>> (methodExp, parameter);
return source.Where (lambda);
}
}
打开Index.aspx并将 URL '/Json/CustomersList' 更新为指向 URL '/Json/FlexigridList'。
现在,您应该拥有一个功能齐全的 ASP.NET MVC / Flexigrid / JSON / LINQ to SQL 演示,足以给您所有朋友留下深刻印象或充实您的简历。
历史
- 2008.10.31 > 首次发布。
- 2008.11.03 > 根据用户反馈更新。