2017-03-06 4 views
5

Ich baue eine ASP.NET MVC 5 App mit Visual Studio 2015. Die Suche funktioniert gut beim ersten Versuch, aber dann, wenn ich eine der Seitenzahlen in der klicken MVC PagedList component, es wirft eine Internal Server Error. Hier ist das AJAX-Formular; beachten Sie, dass sie die Daten von der Suche nach einer Teilansicht empfangen passiert:ASP.NET MVC PagedList mit AJAX in Teilansicht

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

In _PermitsCustomerList Teilansicht, ich habe folgende:

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

Und hier ist die Aktion auf dem Controller:

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

Hier sind die Erfolge und Misserfolge Callback-Funktionen:

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

Ich schaute auf dieses Beispiel: MVC 4 Using Paged List in a partial View und fügte die PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing hinzu, aber etwas fehlt noch.

Wenn ich die Konsolentafel in Chrome zu sehen, hat es diesen Fehler, wenn ich auf einer Seitennummer klicken:

http://localhost:9999/MyProject/Permits/SearchCustomers?page=2 500 (Internal Server Error)

Was mache ich falsch, wenn versuchen, einen AJAX-Anruf mit der Komponente PagedList zu tun?

Antwort

4

Nach vielen trial-and-error, war die Antwort auf keine Aussicht Modellfeld für die Suche zu verwenden.

Hier ist das neue Suchfeld in der Hauptansicht:

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

Dann in der Aktion, diese Änderung erhält die searchName Wert:

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

Notiere die ViewBag.SearchName; Dies wird verwendet, um den Suchfeldwert an die Teilansicht zu übergeben.

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

in dem Paging-Mechanismus, der oben, verwenden wir die ViewBag den Suchwert zurück an die Steuerung zu übergeben.

Update 1: Sie müssen auch die folgenden in der Hauptansicht (die die teilweise enthalten), um die Fälschungs Token, um sicherzustellen, wird gesendet, wenn Sie die Zahlen in der Paging klicken:

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

von hier aus: https://gist.github.com/scottrippey/3428114

Update 2: Sie können die Ansicht Modell auf dem Controller verwenden, aber eine RouteValueDictionary passieren müssen:

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

Damit würden Sie die Aktion ändern:

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

Die komplexen Objekte auf dem RouteValueDictionary Hilfe kam von hier: https://stackoverflow.com/a/23743358/177416

1

Es sieht so aus, als würden Sie Ihrem Controller kein erforderliches Argument übergeben. Ändern Sie Ihre PagedListPager dazu: (! Meist Fehler)

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