2017-03-06 30 views
5

Buduję aplikację ASP.NET MVC 5 przy użyciu programu Visual Studio 2015. Wyszukiwanie działa poprawnie za pierwszym razem, ale jeśli kliknę dowolny numer strony w MVC PagedList component, rzuca Internal Server Error. Oto formularz AJAX; pamiętać, że przekazuje dane otrzymane z wyszukiwania z częściowym widokiem:PagedList ASP.NET MVC za pomocą AJAX w częściowym widoku

@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> 
} 

W _PermitsCustomerList częściowego widzenia, mam następujące:

@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> 
} 

i tu jest działaniem na kontrolerze:

[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)); 
} 

Oto sukces i porażka oddzwonienia funkcje:

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>"); 
    } 
} 

Spojrzałem na ten przykład: MVC 4 Using Paged List in a partial View i dodano PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing, ale czegoś jeszcze brakuje.

Kiedy wyświetlić panel konsoli w Chrome, ma ten błąd po kliknięciu na numer:

http://localhost:9999/MyProject/Permits/SearchCustomers?page=2 500 (wewnętrzny błąd serwera)

Co robię źle kiedy próbuje wykonać wywołanie AJAX z komponentem PagedList?

Odpowiedz

4

Po wielu prób i błędów, odpowiedź była, aby nie używać pole widoku modelu do wyszukiwania.

Oto nowe pole wyszukiwania w widoku głównym:

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

Następnie w akcji, zmiana ta przyjmuje wartość 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); 
} 

Zanotować ViewBag.SearchName; która będzie używana do przekazania wartości pola wyszukiwania do widoku częściowego.

<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> 

W mechanizmu stronicowania powyżej, używamy ViewBag przekazać wartość wyszukiwania z powrotem do kontrolera.

Aktualizacja 1: Należy również następujące na głównym widoku (jeden zawierający częściowe) w celu zapewnienia ochrony przed fałszowaniem żeton zostaje wysłany po kliknięciu numery w stronicowania:

$.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(); 
     } 
    } 
}); 

stąd: https://gist.github.com/scottrippey/3428114

Aktualizacja 2: można użyć modelu widok na kontrolerze, ale trzeba zdać 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> 

Dzięki temu, można zmienić działanie:

[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); 
} 

Kompleks obiektów pomoc na RouteValueDictionary przyszedł stąd: https://stackoverflow.com/a/23743358/177416

1

Wygląda na to, że nie przekazujesz wymaganego argumentu do kontrolera. Zmienić PagedListPager do tego: (! Przeważnie błędu)

@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" }))