MVC3 - значение параметра всегда нулевое
Я пытаюсь сделать представление "расширенный поиск", используя два частичных представления и Ajax. Я определил сущность "SearchFilter", имеющую в качестве свойств все доступные критерии поиска. При отправке в частичном представлении "_Filter" (AjaxOption OnSuccess) мне нужно передать его в действие "ListResults", которое обновляет частичное представление "_Results".
Проблема в том, что я всегда получаю нулевую сущность в качестве входящего параметра действия ListResults.
Код выглядит следующим образом:
AdvancedSearchView.cshtml
@model MyApp.ViewModels.SearchFormViewModel
@{
ViewBag.Title = "Advanced search";
}
<div id="divFilter">
@Html.Partial("_Filter", Model)
</div>
<div id="divResults">
@Html.Partial("_Results", Model.ResultsList)
</div>
_Filter.cshtml
@model MyApp.ViewModels.SearchFormViewModel
<script type="text/javascript">
function getForm(url, divName) {
var obj = new Date();
url = (url.indexOf('?', 0) != -1) ? url + '&uid=' + obj.getTime() : url + '?uid=' + obj.getTime();
$.get(url, function (data) {
$("#" + divName).html(data);
});
}
</script>
@using (Ajax.BeginForm("Search", null, new AjaxOptions
{
UpdateTargetId = "divFilter",
InsertionMode = InsertionMode.Replace,
OnSuccess="getForm('"+Url.Action("ListResults", "Products", new { myFilter = Model.CurrentFilter}) + "','divResults')"
}, new { id = "idSearchForm" }))
{
<fieldset style="width: 800px; line-height: 1.4em;">
<legend>Configure your search filters</legend>
...
</fieldset>
<input type="submit" value="Rechercher" class="submit" style="width: 280px" />
}
контроллер
public ActionResult Search()
{
SearchFilter currentFilter = new SearchFilter();
List<Product> filteredProductsList = repository.FindProducts_Filtered(currentFilter);
return View("AdvancedSearchView", new AdvancedSearchFormViewModel(currentFilter, filteredProductsList/* , necessary select lists */));
}
[HttpPost]
public ActionResult Search(AdvancedSearchFormViewModel model)
{
SearchFilter currentFilter = model.CurrentFilter;
// set the necessary select lists
List<Product> filteredProductsList = repository.FindProducts_Filtered(currentFilter);
return PartialView("_Filter", AdvancedSearchFormViewModel(currentFilter, filteredProductsList/* , necessary select lists */));
}
public ActionResult ListResults(SearchFilter myFilter)
{
List<Product> filteredProductsList = repository.FindProducts_Filtered(currentFilter);
return PartialView("_Results", filteredProductsList);
}
Модель представления
public class AdvancedSearchFormViewModel
{
// Properties
public SearchFilter CurrentFilter { get; set; }
public List<Product> ResultsList { get; set; }
// some SelectLists
// Constructor
public AdvancedSearchFormViewModel()
{}
public AdvancedSearchFormViewModel(SearchFilter pCurrentFilter, List<Product> pResultsList, /* necessary select lists*/)
{
CurrentFilter = pCurrentFilter;
ResultsList = pResultsList;
// the SelectLists
}
}
Я не сомневаюсь, что делаю что-то не так, но не вижу, что это такое.
Сгенерированная HTML-разметка BeginForm выглядит следующим образом:
<form action="/Products/Search" data-ajax="true" data-ajax-mode="replace" data-ajax-success="getForm('/Products/ListResults?myFilter=MyApp.Models.SearchFilter&uid=2622ea0e-d7dc-48fa-b65d-519978ee40b3','divResults')" data-ajax-update="#divFilter" id="idSearchForm" method="post">
1 ответ
Причина, по которой вы получаете нулевое значение для аргумента myFilter действия ListResults, заключается в том, что вы отправляете это на сервер:
/Products/ListResults?myFilter=MyApp.Models.SearchFilter&uid=2622ea0e-d7...
Моделиндер по умолчанию пытается превратить строку "MyApp.Models.SearchFilter" в экземпляр MyApp.Models.SearchFilter, чего он не может сделать.
Я не вижу кода для этого объекта модели, но вы должны попробовать отправить каждый из параметров по отдельности, чтобы связыватель модели мог создать экземпляр SearchFilter из его свойств:
OnSuccess="getForm('"+Url.Action("ListResults", "Products", new {
Prop1 = Model.CurrentFilter.Prop1,
Prop2 = Model.CurrentFilter.Prop2,
etc...
})...
Обновление после комментария 1
Чтобы ответить на ваш вопрос об отображении значений параметров в URL, вот как работает HTTP. Если вы не хотите показывать какие-либо параметры, отправленные на сервер в URL-адресе, вам нужно будет выполнить HTTP POST вместо HTTP GET.
Однако всякий раз, когда ваша операция идемпотентна, вы должны использовать HTTP GET. HTTP POST должен быть зарезервирован для случаев, когда отправка ввода должна каким-то образом изменять состояние приложения. На самом деле, я не согласен с тем, что вы используете [HttpPost] для вашего public ActionResult Search(AdvancedSearchFormViewModel model)
метод действия. Поскольку все, что он делает, это возвращает данные для просмотра, это идемпотентное действие.
Тем не менее, ничто не мешает вам нарушить это правило и выполнить HTTP POST вместо GET. Лично я не вижу проблемы с параметрами URL. Вы видите их все время в Интернете. Например, посмотрите URL для этой ссылки.
HTTP не понимает сложные объекты, только текст. Чтобы отправлять данные для сложных объектов по HTTP, их необходимо разбить на текстовые части. Чтобы отправлять такие данные через HTTP GET, они должны быть в URL.