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

MVC 基础站点:第 4 步 – 在 MVC 4.0 中使用 AJAX、JSON、jQuery、LINQ 和序列化集成 jqGrid

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (90投票s)

2013年5月16日

Ms-PL

16分钟阅读

viewsIcon

423854

downloadIcon

23837

本文详细介绍了在 MVC 4.0 中使用 AJAX、JSON、jQuery、LINQ 和序列化集成 jqGrid。

MVC 基本站点

目录

引言

MVC 基本站点旨在成为一系列关于创建使用 ASP.NET MVC 的基本且可扩展网站的教程文章。

本系列的第一篇文章,名为 MVC 基础站点:第 1 步 - 多语言站点框架,主要侧重于使用 ASP.NET MVC 创建多语言网站框架。此外,还介绍了从头开始的用户身份验证和注册。

第二篇文章 MVC 基础站点:第 2 步 - 异常管理,详细介绍了 ASP.NET MVC 网站的异常管理规则及其实现,并提供了一些可重用的日志记录和异常管理实用基类和源代码(只需稍作修改),不仅可用于其他 ASP.NET 网站,也可用于任何 .NET 项目。

第三篇文章 MVC 基础站点:第 3 步 - 使用 AJAX、jqGrid、Controller Extensions、HTML Helpers 等实现动态布局和站点管理,介绍了使用 AJAX、jqGrid、自定义 Action Results、Controller Extension、HTML Helpers 以及其他实用的 C# 源代码和 JavaScript 来实现动态布局和网站管理,这些都可以扩展并重用于其他项目。

本文是 MVC 基础站点系列中的第四篇,详细介绍了在 MVC 4.0 中使用 AJAX、JSON、jQuery、LINQ 和序列化集成 jqGrid

MVC 基础站点采用增量和迭代的方法进行开发,这意味着每一步都会在上一歩的基础上添加更多功能,因此本文提供的下载源代码包含了迄今为止实现的所有功能(来自所有文章)。

请注意,所有提供的源代码都经过良好注释且清晰,阅读和理解它们应该没有问题。

本文的第一部分描述了所使用的构建块,下一部分将继续介绍如何使用 AJAX、JSON、JavaScript 以及前面介绍的所有构建块将 jqGrid 集成到 MVC 基础站点解决方案中。

软件环境

  • .NET 4.0 框架
  • Visual Studio 2010(或 Express 版)
  • ASP.NET MVC 4.0
  • SQL Server 2008 R2(或 Express Edition 版本 10.50.2500.0)

jqGrid 和 AJAX

jqGrid 是一个开源的 AJAX 启用 JavaScript 控件,它提供了在 Web 上表示和操作表格数据的解决方案,并通过 AJAX 回调动态加载数据。

有关 jqGrid 的文档、开源包、演示和示例可以在以下网站找到:http://www.trirand.com

必须集成到 Web 应用程序中的 jqGrid 包的主要组件是:

  • jquery.jqGrid.min.js – 包含精简后的 jqGrid JavaScript 库;
  • jquery.jqGrid.src.js – 包含源代码形式的 jqGrid JavaScript 库;
  • ui.jqgrid.css – 上述库使用的 CSS;
  • 一组特定语言的文件,名为 grid.locale-XX.js,其中 XX 是语言的两位字母代码。

除了这些主要组件之外,还建议通过使用工具 https://jqueryui.jqueryjs.cn/themeroller/ 来自定义、下载和使用一个或多个 jQuery UI 主题。在当前解决方案中,我使用了 Redmond 主题的自定义版本。

AJAX 是 Asynchronous JavaScript and XML 的常用缩写。AJAX 不是单一技术,而是一组相互关联的 Web 开发技术,用于创建异步 Web 应用程序。通过 AJAX,Web 应用程序可以异步地将数据发送到 Web 服务器并从中检索数据,而不会干扰现有页面的显示和行为,从而避免了整个页面的重新加载。

在下面的图表中,我使用 UML 图展示了经典 Web 系统模型和 AJAX Web 系统模型。

从上图可以看出,在经典模型中,用户从用户界面组件(来自浏览器客户端)的每次请求都会直接向 Web 应用程序(运行在 Web 服务器上)发送一个 HTTP 请求,Web 应用程序进行一些处理,然后将响应作为 HTML 页面(HTTP + CSS)发送回浏览器,最后浏览器渲染整个响应。

在基于 AJAX 的 Web 应用程序中,当用户发出请求时,用户界面组件会向浏览器的 AJAX 引擎组件发送一个 JavaScript 调用。该引擎负责呈现用户看到的界面,并代表用户与服务器通信。AJAX 引擎允许用户的应用程序交互异步进行——独立于与服务器的通信。请注意,AJAX 引擎向 Web 应用程序发送 HTTP 请求,并接收回仅需的数据(而不是整个 HTML 页面),格式为 XML。

GridSettings

这是我创建的用于存储 jqGrid 设置以及进行分页和排序的主要 类。

从上方的类图可以看出,有四个属性用于存储当前的网格设置。

  • PageIndex:存储当前页码(1 是第一页,2 是第二页,依此类推);
  • PageSize:存储页面大小(一页网格中加载和显示的行数最大值);
  • SortColumn:当前排序的列;
  • SortOrder:当前排序顺序(ASCDESC)。

此类实现了 Serializable 接口,因此它重写了 ToString() 方法将当前网格设置缓存到字符串中,并提供了一个第二个构造函数,用于从序列化数据初始化 GridSettings 类的新实例。

在下面的源代码中,您可以看到此类提供的主要方法,用于从给定数据源加载当前网格设置的数据。请注意,数据源参数应该是使用 LINQ 创建的查询。

public IQueryable<T> LoadGridData<T>(IQueryable<T> dataSource, out int count)
{
    var query = dataSource;
    //
    // Sorting and Paging by using the current grid settings.
    //
    query = query.OrderBy<T>(this.SortColumn, this.SortOrder);
    count = query.Count();
    //
    if (this.PageIndex < 1)
        this.PageIndex = 1;
    //
    var data = query.Skip((this.PageIndex - 1) * this.PageSize).Take(this.PageSize);
    return data;
}

从上面的代码可以看出,此方法使用泛型,因此它是一个通用方法,可用于加载任何类型的数据,并将其结果计数作为输出参数返回。首先使用网格设置中的参数进行排序,然后计算计数,最后仅从数据库加载请求的页面结果。

请注意,GridSettings 类通过 ModelBinder 属性与 GridModelBinder 类(在下一章中介绍)相关联。

GridModelBinder

ASP.NET MVC 的模型绑定通过引入一个抽象层来简化控制器操作,该层会自动填充控制器操作参数,并处理通常在处理 ASP.NET 请求数据时涉及的属性映射和类型转换代码。

GridModelBinder 是我自定义的模型绑定器类,由 GridSettings 类(在上一章中介绍)使用,用于将其属性与 jqGrid 参数绑定。

从上方的类图可以看出,此类只有一个名为 BindModel 的方法,并使用它来实现 IModelBinder 接口。

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    try
    {
        var request = controllerContext.HttpContext.Request;
        return new GridSettings
        {
            PageIndex = int.Parse(request["page"] ?? "1"),
            PageSize = int.Parse(request["rows"] ?? "20"),
            SortColumn = request["sidx"] ?? "",
            SortOrder = request["sord"] ?? "asc",
        };
    }
    catch
    {
        //
        // For unexpected errors use the default settings!
        //
        return null;
    }
}

从上面的源代码可以看出,来自 jqGrid 通过 JavaScript 调用发送的 HTTP 请求中的参数用于创建和初始化一个新的 GridSettings 对象,该对象将被用作控制器中的模型。

LinqExtensions

此类扩展了 LINQ,以使用我上面描述的 GridSeetings 类中的以下两个参数来简化排序过程:SortColumnSortOrder

从上方的类图可以看出,该类只有一个名为 OrderBy 的静态方法,并且使用了泛型。

public static IQueryable<T> OrderBy<T>(
       this IQueryable<T> query, string sortColumn, string direction)
{
    string methodName = string.Format("OrderBy{0}", 
      direction.ToLower() == "asc" ? "" : "descending");
    ParameterExpression parameter = Expression.Parameter(query.ElementType, "p");
    MemberExpression memberAccess = null;
    //
    foreach (var property in sortColumn.Split('.'))
    {
        memberAccess = MemberExpression.Property(memberAccess ?? (parameter as Expression), property);
    }
    //
    LambdaExpression orderByLambda = Expression.Lambda(memberAccess, parameter);
    MethodCallExpression result = Expression.Call(
                typeof(Queryable),
                methodName,
                new[] { query.ElementType, memberAccess.Type },
                query.Expression,
                Expression.Quote(orderByLambda));
    //
    // For the sortColumn=='User.Username' and  direction=="desc" ==> 
    //           "OrderByDescending(p => p.User.Username)" expression 
    // will be appended to the input query!
    //
    return query.Provider.CreateQuery<T>(result);
}

上面的源代码为给定的排序列和方向(排序顺序)创建了一个 lambda 表达式,然后将结果附加到给定的输入查询。请注意,排序列可以很简单,如“ID”,也可以更复杂,如“User.Username”(这使用了数据实体之间的导航属性)。

数据实体类和 LINQ

本示例中使用的数据实体类名为 VisitorLog(位于 Logic 项目中),它包含一组用于访问 VissitorLogs 数据库表数据的方法。

此类中用于读取最终将显示给用户的 jqGrid 中的访问者日志数据的主要方法是下一个。

public static IQueryable<VisitorLog> SearchLogByDates(MvcBasicSiteEntities dataContext, DateTime searchStartDate, DateTime searchEndDate)
{
    if (searchStartDate.Date == DateTime.MinValue && searchEndDate.Date == DateTime.MinValue)
    {
        return dataContext.VisitorLogs.AsQueryable();
    }
    else if (searchStartDate.Date == DateTime.MinValue)
    {
        var searchResults = dataContext.VisitorLogs.Where(c => 
            EntityFunctions.TruncateTime(c.StartDate) <= EntityFunctions.TruncateTime(searchEndDate));
        //
        return searchResults.AsQueryable();
    }
    else if (searchEndDate.Date == DateTime.MinValue)
    {
        var searchResults = dataContext.VisitorLogs.Where(c => 
            EntityFunctions.TruncateTime(c.StartDate) >= EntityFunctions.TruncateTime(searchStartDate));
        //
        return searchResults.AsQueryable();
    }
    else
    {
        var searchResults = dataContext.VisitorLogs.Where(c =>
            EntityFunctions.TruncateTime(c.StartDate) >= EntityFunctions.TruncateTime(searchStartDate) &&
            EntityFunctions.TruncateTime(c.StartDate) <= EntityFunctions.TruncateTime(searchEndDate));
        //
        return searchResults.AsQueryable();
    }
}

从上面的源代码可以看出,该方法基于给定的参数,为以下 4 种可能的情况构建 LINQ 表达式:

  • 查找两个给定日期间隔之间的所有条目,当两个参数都具有有效值时;有效值是指不同于 DateTime.MinValue 的值;
  • 当两个参数都没有有效值时,从数据库查找所有条目;
  • 当只有一个开始日期具有有效值时,从给定的开始日期查找直到今天的条目;
  • 当只有一个结束日期具有有效值时,查找直到给定结束日期的条目。

在 MVC 中集成 jqGrid

上面介绍的所有构建块都用于将 jqGrid 集成到我的 MVC 解决方案中。要查看此集成的结果,您必须从管理员区域打开“访问者”页面(您必须使用用户名 Administrator 和密码 tm77dac 登录)。

从上方的屏幕截图可以看出,有一个包含五列不同类型(字符串、日期时间、布尔值)的网格,所有列都启用了排序。最后一列“操作”使用了我的 ImageButton 自定义 HTML 助手(在我之前的文章中介绍);当用户点击“操作”列中的“删除”图像按钮时,将从数据库中删除相关的访问者日志条目。

在网格页脚有一个分页控件,显示并允许用户指定网格处理的总结果数、当前页、导航按钮以及每页显示的行数。通过使用所有这些导航控件,用户可以按需在结果之间导航。

在网格页脚还有两个操作按钮:“刷新网格”按钮(图像按钮)和“删除全部”按钮——用于删除当前过滤器下的所有访问者日志历史记录。

请注意,此页面以及整个 MVC 基础站点解决方案都是通过国际化和本地化来实现的,支持三种语言:英语、罗马尼亚语 (Română) 和德语 (Deutch),并且可以扩展到其他语言;因此,此页面上的消息和控件(标签、按钮、工具提示等)也是多语言的。

jqGrid 集成到此 MVC 解决方案中是通过以下四个步骤完成的。您可以遵循类似的步骤将 jqGrid 集成到您的 MVC 应用程序中。

第 1 步 (部分视图)

在创建了上述构建块之后,我集成 jqGrid 所遵循的第一个步骤是创建一个名为 _VisitorLogGrid.cshtml 的部分视图,它将作为网格及其分页控件的容器。

<table id="_visitorLogGrid" cellpadding="0" cellspacing="0">
</table>
<div id="_visitorLogPager" style="text-align: center;">
</div>

上面 HTML 代码中定义的两个 ID 非常重要,因为它们将在后续步骤中使用。

第 2 步 (JavaScript)

第二步是创建一个名为 VisitorLogGrid.js 的 JavaScript 文件,并将其放置在 Scripts 文件夹中。

function showGrid() {
    $('#_visitorLogGrid').jqGrid({
        caption: paramFromView.Caption,
        colNames: ['ID', paramFromView.VisitorName, paramFromView.StartDate, 
          paramFromView.EndDate, paramFromView.WasTimeOut, paramFromView.Actions],
        colModel: [
                    { name: 'ID', width: 1, hidden: true, key: true },
                    { name: 'VisitorName', index: 'User.Username', width: 300 },
                    { name: 'StartDate', index: 'StartDate', width: 150 },
                    { name: 'EndDate', index: 'EndDate', width: 150 },
                    { name: 'WasTimeOut', index: 'WasTimeOut', width: 120, 
                            formatter: "checkbox", align: "center" },
                    { name: 'Action', index: 'ID', width: 70, align: "center" }
                  ],
        hidegrid: false,
        pager: jQuery('#_visitorLogPager'),
        sortname: 'ID',
        rowNum: paramFromView.PageSize,
        rowList: [10, 20, 50, 100],
        sortorder: "desc",
        width: paramFromView.Width,
        height: paramFromView.Height,
        datatype: 'json',
        caption: paramFromView.Caption,
        viewrecords: true,
        mtype: 'GET',
        jsonReader: {
            root: "rows",
            page: "page",
            total: "total",
            records: "records",
            repeatitems: false,
            userdata: "userdata"
        },
        url: paramFromView.Url
    }).navGrid('#_visitorLogPager', { view: false, del: false, add: false, edit: false, search: false },
       { width: 400 }, // default settings for edit
       {}, // default settings for add
       {}, // delete instead that del:false we need this
       {}, // search options
       {} /* view parameters*/
     ).navButtonAdd('#_visitorLogPager', {
         caption: paramFromView.DeleteAllCaption, buttonimg: "", onClickButton: function () {
             if (confirm(paramFromView.DeleteAllConfirmationMessage)) {
                 document.location = paramFromView.ClearGridUrl;
             }
             else {
                 $('#_visitorLogGrid').resetSelection();
             }
         }, position: "last"
     });
};

$(document).ready(function () {
    showGrid();
});

从上面的 JavaScript 代码可以看出,定义了一个 document.ready 事件,用于在文档就绪时显示网格,以及一个名为 showGrid 的主函数,该函数定义了 jqGrid 的列、属性、分页控件和导航按钮。

请注意,网格标题、列定义、按钮和消息中使用的所有标签都使用来自资源文件的值,通过 paramFromView 对象的属性获取(下文有详细说明)。

有一些重要细节必须强调:

  • _visitorLogGrid 是上面部分视图中定义的表格的 ID,用于创建网格;
  • _visitorLogPager 是上面部分视图中定义的 div 的 ID,用于创建分页控件以及与网格关联的导航按钮(“刷新”和“删除全部”);
  • colNames 属性定义了所有网格列的名称(包括隐藏列);
  • colModel 属性定义了列的行为和属性,包括与数据实体属性关联的排序索引;
  • rowNum 属性设置网格的当前页面大小(每页的行数),通过使用 paramFromView 对象的 PageSize 属性;
  • width 属性设置网格控件的宽度(以像素为单位),通过使用 paramFromView 对象的 Width 属性;
  • hight 属性设置网格控件的高度(以像素为单位),通过使用 paramFromView 对象的 Height 属性;
  • url 属性设置 jqGrid 通过 AJAX 调用从服务器获取数据时使用的 URL,通过使用 paramFromView 对象的 Url 属性;
  • 删除全部导航按钮使用 paramFromView 对象的 ClearGridUrl 属性来设置用户确认“删除全部”操作时使用的 URL。
  • jsonReader 属性定义了将从服务器读取的 JSON 数据中使用的主要属性的名称(详见第 4 步)。

第 3 步 (Razor 视图)

第三步是创建将使用第二个步骤中的 JavaScript 文件的主要页面。它位于 Views\VisitorsLog 文件夹中的 Index.cshtml 视图。

@using MvcBasicSite.Models.Grid;
@{
    ViewBag.Title = Resources.Resource.VisitorLogIndexTitle;
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
    //
    int pageSize = 20;
    if (Session["VisitorLogGridSettings"] != null)
    {
        //
        // Get from cache the last page zise selected by the user. 
        //
        GridSettings grid = new GridSettings((string)Session["VisitorLogGridSettings"]);
        pageSize = grid.PageSize;
    }
    //
    // Restore the last search params from cache.
    //
    string startDate = (Session["StartDate"] == null
        ? string.Empty
        : ((DateTime)Session["StartDate"]).ToShortDateString());
    string endDate = (Session["EndDate"] == null
        ? string.Empty
        : ((DateTime)Session["EndDate"]).ToShortDateString());
}
<table>
    <tr>
        <td style="text-align: right; margin-top: 0px;">
            @using (Ajax.BeginForm("Search", "VisitorLog", 
                new AjaxOptions
                {
                    HttpMethod = "GET",
                    InsertionMode = InsertionMode.Replace,
                    UpdateTargetId = "jqGrid",
                    OnSuccess = "showGrid()"
                }))
            {
                <table>
                    <tr>
                        <td>
                            <label>@Resources.Resource.VisitorLogIndexFrom</label>
                            <input type="text" id="from" name="from" 
                              data-datepicker="true" value="@startDate" />
                        </td>
                        <td>
                            <label>@Resources.Resource.VisitorLogIndexTo</label>
                            <input type="text" id="to" name="to" 
                              data-datepicker="true" value="@endDate" />
                        </td>
                        <td style="text-align: right; margin-top: 0px;">
                            <input type="submit" name="_search" 
                              value="@Resources.Resource.VisitorLogApplyFilter" 
                              class="searchButton" />
                        </td>
                    </tr>
                </table>
            }
        </td>
    </tr>
</table>
<div id="jqGrid">
    @Html.Partial("_VisitorLogGrid")
</div>
<script type="text/javascript">
    var paramFromView = {
        DeleteAllCaption: '@Resources.Resource.VisitorLogDeleteAllCaption',
        ClearGridUrl: '@Url.Content("~/VisitorLog/ClearGridData")',
        DeleteAllConfirmationMessage: '@Resources.Resource.VisitorLogDeleteAllDataConfirmation',
        Url: '@Url.Content("~/VisitorLog/GetData")',
        Width: 790,
        Height: 464,
        Caption: '@Resources.Resource.VisitorLogIndexTitle',
        VisitorName: '@Resources.Resource.VisitorLogIndexVisitorName',
        StartDate: '@Resources.Resource.VisitorLogIndexStartDate',
        EndDate: '@Resources.Resource.VisitorLogIndexEndDate',
        WasTimeOut: '@Resources.Resource.VisitorLogIndexWasTimeOut',
        Actions: '@Resources.Resource.VisitorLogIndexActions',
        PageSize: @pageSize
    }
</script>
@section scripts
{
    @Content.Script("VisitorLogGrid.js", Url)
}

在上面 Razor 视图的第一部分,在设置页面标题和布局后,我从 HTTP 会话中获取了页面上最后使用的网格设置和搜索参数(开始日期和结束日期)。

然后有一个表格用于通过开始日期和结束日期过滤结果。请注意,AJAX 用于仅获取所需数据,通过调用 VisitiorLog 控制器的 Search 操作,并在成功时使用 JavaScript 函数 showGrid(在第 2 步中定义),并且仅更新页面中包含网格的部分区域。

为了渲染网格,使用了部分视图和 JavaScript 代码,如以上各步骤所述,通过使用 Razor 块:@Html.Partial("_VisitorLogGrid")@Content.Script("VisitorLogGrid.js", Url)

在视图的最后是一个内联 JavaScript 部分,用于创建和初始化一个 paramFromView 对象,该对象在第二个步骤的 JavaScript 代码中使用。这样,我们就动态地传递了最后一次网格设置(用户在执行过程中可以通过 UI 进行更改),以及从适当的资源文件中读取的标签、按钮文本和消息的值(基于当前选定的语言)。请注意,与控制器操作相关的以下两个 URL 也在此处设置:

  • VisitorLog/GetData - 获取网格的数据;
  • VisitorLog/ClearGridData - 删除当前过滤器匹配的所有数据。

第 4 步 (控制器)

现在是时候进入 VisitorLogController 类来实现从视图调用的操作了。

JavaScript 代码通过 AJAX 调用以加载 jqGrid 使用的、并使用网格设置的数据的主要方法是下一个:

public JsonResult GetData(GridSettings grid)
{
    if (_fromIndex && Session["VisitorLogGridSettings"] != null)
    {
        //
        // Get grid settings from cache!
        //
        grid = new GridSettings((str ing)Session["VisitorLogGridSettings"]);
    }
    //
    _fromIndex = false; // Must be set on false here!
    //
    // Load the data from the database for the current grid settings.
    //
    DateTime searchStartDate = (Session["StartDate"] == null ? 
      DateTime.MinValue : (DateTime)Session["StartDate"]);
    DateTime searchEndDate = (Session["EndDate"] == null ? 
      DateTime.MinValue : (DateTime)Session["EndDate"]);
    int count;
    var query = grid.LoadGridData<VisitorLog>(
      VisitorLog.SearchLogByDates(_db, searchStartDate, searchEndDate), out count);
    var data = query.ToArray();
    //
    // Convert the results in JSON jqGrid format.
    //
    string gridSettingsString = grid.ToString(); // Used to preserve grid settings!
    Session["VisitorLogGridSettings"] = gridSettingsString;
    gridSettingsString = null;
    var result = new
    {
        total = (int)Math.Ceiling((double)count / grid.PageSize),
        page = grid.PageIndex,
        records = count,
        rows = (from host in data
                select new
                {
                    ID = host.ID,
                    VisitorName = GetVisitorNameForBinding(host),
                    StartDate = host.StartDate.ToString(),
                    EndDate = host.EndDate.ToString(),
                    WasTimeOut = (host.WasTimeOut ?? false),
                    Action = string.Format("{0}", 
                                    RenderHelpers.ImageButton(
                                            this, 
                                            Resources.Resource.DeleteTip,
                                            "~/Content/Images/Delete.gif",
                                            "Delete", 
                                            new { id = host.ID }, 
                                            new { style = "border:0px;" }))
                }).ToArray()
    };
    //
    // Convert to JsonResult before to return.
    //
    return Json(result, JsonRequestBehavior.AllowGet);
}

在上面的代码中,您可以看到作为参数的 GridSettings 对象通过我们自定义的 GriModelBinder(在上一章中介绍)进行初始化,并用于发送用户在用户界面中为分页和排序所做的选择。然后,该对象或从缓存数据创建的对象(当用户从另一页返回时)用于加载当前过滤器的数据并创建当前页的行。最后,结果被转换为 JSON 格式进行返回。

JSON,即 JavaScript Object Notation,是一种基于文本的开放标准,专为数据交换而设计。它源自 JavaScript 脚本语言,用于表示简单的数据结构和关联数组,但其文本格式与语言完全无关。

请注意,在上面的源代码中,创建了一个名为 result 的 JSON 对象,它具有四个属性(totalpagerecordsrows),这些属性的名称与在第 2 步的 JavaScript 中定义的名称相同。此外,rows 属性包含网格的行数据(当前页),并且 JSON 中定义的每一行都必须初始化第 2 步中 jqGrid colModel 属性中定义的所有属性。

在下面的图片中,您可以看到 访问者(索引)页面在用户通过日期选择器控件指定开始日期和结束日期来过滤结果时的操作。

当用户按下“应用过滤器”按钮时,通过 AJAX 调用以下操作方法,以指定的开始日期和/或结束日期来搜索访问者日志条目。

public PartialViewResult Search()
{
    string startDate = Request["from"];
    string endDate = Request["to"];
    //
    // Cache the start and end dates into the session to be used by later one in the view.
    //
    Session["StartDate"] = (startDate.Length < 1 ? null : 
      (object)DateTime.Parse(startDate, Thread.CurrentThread.CurrentCulture));
    Session["EndDate"] = (endDate.Length < 1 ? null : 
      (object)DateTime.Parse(endDate, Thread.CurrentThread.CurrentCulture));
    //
    return PartialView("_VisitorLogGrid");
}

上面的代码获取请求中的参数,然后缓存其值以供稍后在视图中使用,最后渲染 _VisitorLogGrid 部分视图。

第三个方法响应用户请求,间接通过 JavaScript 代码调用,以删除与当前过滤器匹配的访问者日志。

public ActionResult ClearGridData()
{
    DateTime searchStartDate = (Session["StartDate"] == null ? 
      DateTime.MinValue : (DateTime)Session["StartDate"]);
    DateTime searchEndDate = (Session["EndDate"] == null ? 
      DateTime.MinValue : (DateTime)Session["EndDate"]);
    VisitorLog.DeleteLogByDates(_db, searchStartDate, searchEndDate);
    //
    return RedirectToAction("Index");
}

上面的代码使用缓存中的当前开始日期和结束日期参数,从数据库中删除与当前搜索过滤器匹配的条目,然后重定向到索引页面。

运行此代码之前

在运行此代码之前,您应该执行以下步骤:

  1. 通过以管理员身份运行 CreateEventLogEntry 应用程序来在事件日志中创建一个新条目(CreateEventLogEntry 应用程序源代码作为我们解决方案的一部分提供);
  2. 在您的 SQL Server(或 SQL Express)中创建一个名为 MvcBasicSite 的数据库,然后将提供的 MvcBasicSiteDatabase.bak 数据库恢复到其中。
  3. 根据您在第 2 步中设置的配置修改 MvcBasicSite Web 应用程序的 Web.config 文件中的连接字符串。

如果您觉得本文和提供的源代码有帮助,请投我一票;如果您有任何问题,我将竭诚为您服务!

参考资料

历史记录

  • 2013 年 5 月 16 日:版本 1.0.0.1 - 草稿版本。
  • 2013 年 5 月 24 日:版本 1.0.1.1 - 添加了一些新细节。
  • 2013 年 6 月 1 日:版本 1.0.2.1 - 添加了新章节。
  • 2013 年 6 月 8 日:版本 1.0.2.2 - 添加了一些新细节。
© . All rights reserved.