ASP.NET MVC PagedList 在局部视图中使用 AJAX

5
我正在使用Visual Studio 2015构建一个ASP.NET MVC 5应用程序。搜索在第一次尝试时正常工作,但是如果我点击MVC PagedList组件中的任何一页编号,它会抛出一个内部服务器错误。这是AJAX表单;请注意,它将从搜索接收到的数据传递给一个局部视图:
@using (Ajax.BeginForm("SearchCustomers", "Permits",
new AjaxOptions
{
    UpdateTargetId = "targetElement",
    OnSuccess = "onAjaxSuccess",
    OnFailure = "onAjaxFailure"
},
new { @class = "form-horizontal form-small", role = "form", id="customerSearchForm" }))
{
    @Html.AntiForgeryToken()
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
        <h4>Customer Search</h4>
    </div>
    <div class="modal-body">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group-sm clearfix">
            @Html.LabelFor(m => m.SearchVm.SearchCustomerNameNumber, new { @class = "control-label col-xs-5 col-md-5" })
            <div class="col-xs-5 col-md-5">
                <div class="input-group">
                    @Html.EditorFor(m => m.SearchVm.SearchCustomerNameNumber, new {htmlAttributes = new {@class = "form-control"}})
                    <span class="input-group-btn">
                        <button type="submit" class="btn btn-custom-success btn-sm btn-custom-sm small-box-shadow btn-block">
                            Search
                            <i class="fa fa-search fa-lg" aria-hidden="true"></i>
                        </button>
                    </span>
                </div>
                @Html.ValidationMessageFor(m => m.SearchVm.SearchCustomerNameNumber, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="modal-search" id="targetElement">
            @Html.Partial("_PermitsCustomerList", Model.SearchVm.Customers)
        </div>
    </div>
}

_PermitsCustomerList局部视图中,我有以下内容:
@using PagedList
@using PagedList.Mvc
@model IPagedList<MyProject.ViewModels.CustomerViewModel>
@if (Model != null && Model.Count > 0)
{
    <div class="panel panel-default data-grid data-grid-wide">
        <table class="table table-hover table-striped table-bordered table-responsive">
            <tr>
                <th>
                    Customer #
                </th>
                <th>
                    Customer Name
                </th>
            </tr>
            @foreach (var item in Model)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.Customer_NO)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Customer_Name)
                    </td>
                </tr>
            }
        </table>
        <div id="contentPager">
            @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", 
               new { page }), 
               PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions()
       {
           HttpMethod = "POST",
           UpdateTargetId = "targetElement",
           OnSuccess = "onAjaxSuccess",
           OnFailure = "onAjaxFailure"
       }))
        </div>
    </div>
}

这是控制器上的操作:

[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult SearchCustomers(PermitsViewModel permitsVm, int? page)
{
    if (string.IsNullOrEmpty(permitsVm.SearchVm.SearchCustomerNameNumber)) return null;
    permitsVm.Page = page;
    int number;
    var list = int.TryParse(permitsVm.SearchVm.SearchCustomerNameNumber, out number) 
       ? CustomerDataService.SearchCustomerByNumber(number) 
       : CustomerDataService.SearchCustomerByName(permitsVm.SearchVm.SearchCustomerNameNumber);

    return PartialView("_PermitsCreateCustomerList", list.ToPagedList(permitsVm.Page ?? 1, 10));
}

以下是成功和失败回调函数:

成功回调函数:

失败回调函数:

function onAjaxFailure(xhr, status, error) {
    $("#targetElement").html("<strong>An error occurred retrieving data:" + error + "<br/>.</strong>");
}
function onAjaxSuccess(data, status, xhr) {
    if (!$.trim(data)) {
        $("#targetElement").html("<div class='text-center'><strong>No results found for search.</strong></div>");
    }
}

我看了这个例子:MVC 4 使用 Paged List 在 partial View 中 并添加了 PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing,但仍然缺少一些东西。
当我在 Chrome 中查看控制台面板时,在单击页面编号时会出现以下错误:

http://localhost:9999/MyProject/Permits/SearchCustomers?page=2 500 (内部服务器错误)

当尝试使用 PagedList 组件进行 AJAX 调用时,我做错了什么?
2个回答

4

经过多次试验(大部分是失败的),答案是不使用视图模型字段进行搜索。

这是主视图中的新搜索字段:

@{
    string searchName = ViewBag.SearchName;
}
@Html.EditorFor(x => searchName, new {htmlAttributes = new {@class = "form-control"}})

在操作中,这个变化接收到了 searchName 的值:

[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult CreateSearch(string searchName, int? page)
{
    if (string.IsNullOrEmpty(searchName)) return null;
    int number;
    var list = int.TryParse(searchName, out number) 
        ? CustomerDataService.SearchCustomerByNumber(number) 
        : CustomerDataService.SearchCustomerByName(searchName);
    var permitsVm = new PermitsViewModel 
        {SearchVm = {Customers = list.ToPagedList(page ?? 1, 20)}};
    ViewBag.SearchName = searchName;
    return PartialView("_PermitsCreateCustomerList", permitsVm);
}

请注意ViewBag.SearchName;它将用于将搜索字段值传递给局部视图。
<div id="contentPager">
    @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", 
       new { ViewBag.SearchName, page }), 
       PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions()
{
   HttpMethod = "POST",
   UpdateTargetId = "targetElement",
   OnSuccess = "onAjaxSuccess",
   OnFailure = "onAjaxFailure"
}))
</div>

在上述的分页机制中,我们使用ViewBag将搜索值传回控制器。 更新1: 您还需要在主视图(包含部分视图的视图)上添加以下内容,以确保在单击分页中的数字时发送防伪令牌:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:
        if (options.contentType.indexOf('application/json') === 0) {
            // Add the token to the URL, because we can't add it to the JSON data:
            options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();
        } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {
            // Append to the data string:
            options.data += (options.data ? "&" : "") + token.serialize();
        }
    }
});

从这里开始:https://gist.github.com/scottrippey/3428114 更新2:您可以在控制器上使用视图模型,但必须传递RouteValueDictionary。
<div id="contentPager">
    @Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits", 
       new RouteValueDictionary()
    {
        { "Page", page},
        { "SearchVm.SearchCustomerNameNumber", Model.SearchVm.SearchCustomerNameNumber }
    }), 
       PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions()
    {
       HttpMethod = "POST",
       UpdateTargetId = "targetElement",
       OnSuccess = "onAjaxSuccess",
       OnFailure = "onAjaxFailure"
    }))
</div>

使用这个,您可以更改操作:

[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult CreateSearch(PermitsViewModel permitsVm)
{
    if (string.IsNullOrEmpty(permitsVm.SearchVm.SearchCustomerNameNumber)) return null;
    int number;
    var list = int.TryParse(permitsVm.SearchVm.SearchCustomerNameNumber, out number) 
        ? CustomerDataService.SearchCustomerByNumber(number) 
        : CustomerDataService.SearchCustomerByName(permitsVm.SearchVm.SearchCustomerNameNumber);
    permitsVm.SearchVm.Customers = list.ToPagedList(permitsVm.Page ?? 1, 10);
    return PartialView("_PermitsCreateCustomerList", permitsVm);
}

这里提供了关于RouteValueDictionary的复杂对象的帮助:https://dev59.com/umAg5IYBdhLWcg3wU5cS#23743358


1

看起来您没有将必需的参数传递给控制器。请将您的PagedListPager更改为以下内容:

@Html.PagedListPager(Model, page => Url.Action("SearchCustomers", "Permits",
new { page = page, permitsVm = Json.Encode(Model)}), 
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing( new AjaxOptions()
{
   HttpMethod = "POST",
   UpdateTargetId = "targetElement",
   OnSuccess = "onAjaxSuccess",
   OnFailure = "onAjaxFailure"
}))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接