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

ASP.NET MVC Flexigrid 示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (38投票s)

2008年10月31日

CPOL

7分钟阅读

viewsIcon

589455

downloadIcon

18251

如何使用 LINQ to SQL、用于 JQuery 的 Flexigrid 和 JSON 创建一个 ASP.NET MVC 示例。

flexigrid.jpg

引言

本文将分步演示如何使用 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

创建新项目

第一步是创建一个新的 ASP.NET MVC Web Application 项目。

在本示例中,我们不介绍单元测试,因此在“Create Unit Test Project”对话框中选择“No”。

现在已经创建了一个骨架项目,我们可以进行一些清理。让我们删除一些本次示例中不会用到的项。

  • 请删除AccountController.cs、Views 下的Account文件夹、About.aspxLoginUserControl.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>
  • 打开HomeController.cs,删除About方法,并删除Index方法中的所有内容,除了return View();

清理完成后,项目应如下所示

现在调试应用程序,确保一切正常运行。

添加数据库

接下来,将Northwind.mdfNorthwind_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 演示,足以给您所有朋友留下深刻印象或充实您的简历。

flexigrid-complete.jpg

历史

  • 2008.10.31 > 首次发布。
  • 2008.11.03 > 根据用户反馈更新。
© . All rights reserved.