Я работаю в веб-приложении ASP.NET, используя шаблон MVC.
Я пытаюсь отправить или передать ObjectViewModel из View.cshtml в контроллер, но в контроллере ObjectViewModel прибыл как null.
Идея заключается в следующем: я показываю представление IndexUsersInActiveDirectory.cshtml с коллекцией объекта типа RegisterViewModel. В этом представлении есть @Html.ActionLink для отправки элемента коллекции в контроллер регистра:
IndexUsersInActiveDirectory.csthml
@model IEnumerable<SecureEscuelaWithIdentity.Models.RegisterViewModel>
@{
ViewBag.Title = "IndexUsersInActiveDirectory";
}
<h2>IndexUsersInActiveDirectory</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.UserName)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Select", "Register", new { item })
</td>
</tr>
}
</table>
Регистр контроллера следующий:
//
// GET: /Account/Register
[Authorize(Roles = "Admin")]
public ActionResult Register(RegisterViewModel model)
{
return View(model);
}
Класс RegisterViewModel:
public class RegisterViewModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[Display(Name = "Email")]
public string Email { get; set; }
}
View Register.cshtml
@model SecureEscuelaWithIdentity.Models.RegisterViewModel
@{
ViewBag.Title = "Register";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("RegisterInApp", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
@Html.ValidationSummary()
<li>@Html.ActionLink("ActiveDirectory", "IndexUsersInActiveDirectory", "Account")</li>
<div class="form-group">
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Как отправить весь элемент коллекции (как модель) на контроллер?
@Html.ActionLink("Select", "Register", new { item }, null)
Без этого 4-го параметра он принимает третий параметр - это атрибуты HTML, а не параметры запроса.
Я считаю, что этот маленький 4-й параметр "quirk" является одним из самых раздражающих переопределений в MVC.
item
должен быть простым значением данных, которое может быть передано через строку запросаПоскольку ваш элемент не является простым типом значения, вам необходимо передать его уникальные значения. например:
@Html.ActionLink("Select", "Register", new { name = item.Name, email = item.Email }, null)
Ссылки на действия не делают обратной передачи, они просто создают привязывающие ссылки на странице, поэтому любые значения должны быть переданы в строке запроса.
Измените действие приема, чтобы оно соответствовало:
[Authorize(Roles = "Admin")]
public ActionResult Register(string name, string email)
{
RegisterViewModel model = new RegisterViewModel()
{
Name = name,
Email = email
};
return View(model);
}
Но я оставляю эти детали до вас :)
Решение, предлагаемое TrueBlueAussie, подходит для сценариев, в которых нет проблемы с отображением строки запроса в адресной строке браузера.
Если это так, @Html.ActionLink может выглядеть так:
@Html.ActionLink("Select", "Register", new {item}, null)
так как контроллер возьмет "элемент" как объект RegisterViewModel (хотя на самом деле это будет запрос). Примечание: не забывая 4-й параметр, который внес TrueBlueAussie "null".
Контроллер регистра выглядит следующим образом:
[Authorize (Roles = "Admin")]
public ActionResult Register (RegisterViewModel model)
{
return View (model);
}
Оно работает!
Как упоминалось выше, это отображает запрос в представлении "Регистр", что неверно в моей реализации. Я не хочу показывать эту строку запроса в адресной строке.
Для этого я добавил промежуточного контроллера, ответственного за получение "элемента" (от IndexUsersInActiveDirectory.csthml) в качестве объекта RegisterViewModel (на самом деле это запрос) и добавить этот словарь в словарь TempData с помощью ключа, называемого "модель".
Вот контроллер RegisterTemp:
[Authorize (Roles = "Admin")]
public ActionResult RegisterTemp (RegisterViewModel model)
{
TempData ["model"] = model;
return RedirectToAction ("Register");
}
В представлении "IndexUsersInActiveDirectory.csthml" точка @ActionLink указывает на контроллер RegisterTemp, а не на регистр контроллера, который выглядит следующим образом:
@ Html.ActionLink ("Select", "RegisterTemp", new {item}, null)
Важно, что RegisterTemp возвращает вид "RedirectToAction" в регистр.
И, наконец, когда контроллер RegisterTemp возвращает контроллер RedirectToAction для регистрации, он берет элемент с "модельным" ключом из словаря TempData, чтобы вернуть его в представление. Таким образом, контроллер регистра:
//
// GET: / Account / Register
[Authorize (Roles = "Admin")]
public ActionResult Register ()
{
return View (TempData ["model"]);
}
Я упомянул, что решение, предложенное @TrueBlueAussie, полностью функционально для сценария, что не важно, чтобы показать запрос.
Решение, которое я только что рассмотрел сейчас, заключается в том, чтобы не показывать эту последовательность.
Если есть более правильное решение для решения моего сценария, приветствуется.
Вы должны перебирать элементы с помощью цикла "for", например in (int i; я <= elements.Length -1; i++) элементы [i].etc;
Таким образом, сбор не теряется на почте.
Читайте это для более подробной информации: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/