MVC 4 ViewModel не отправляется обратно контроллеру
Я не могу понять, как отправить весь ViewModel на контроллер на функцию "Проверить и сохранить".
Вот мой контроллер:
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel transaction)
{
}
Вот форма в представлении:
<li class="check">
<h3>Transaction Id</h3>
<p>@Html.DisplayFor(m => m.Transaction.TransactionId)</p>
</li>
<li class="money">
<h3>Deposited Amount</h3>
<p>@Model.Transaction.Amount.ToString() BTC</p>
</li>
<li class="time">
<h3>Time</h3>
<p>@Model.Transaction.Time.ToString()</p>
</li>
@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { transaction = Model }))
{
@Html.HiddenFor(m => m.Token);
@Html.HiddenFor(m => m.Transaction.TransactionId);
@Html.TextBoxFor(m => m.WalletAddress, new { placeholder = "Wallet Address", maxlength = "34" })
<input type="submit" value="Send" />
@Html.ValidationMessage("walletAddress", new { @class = "validation" })
}
Когда я нажимаю кнопку "Отправить", счетчик содержит правильное значение поля walletAddress, но transaction.Transaction.Time
, transaction.Transaction.Location
, transaction.Transaction.TransactionId
пусты.
Есть ли способ передать всю модель обратно контроллеру?
Edit:
Когда я даже не получаю walletAddress
в контроллере. Все становится нулевым!
Когда я удаляю только эту строку: @Html.HiddenFor(m => m.Transaction.TransactionId);
он работает, и я получаю свойство Token на контроллере, но когда я его добавляю, все свойства объекта transaction
на контроллере равны NULL.
Вот биткойнTransactionViewModel:
public class BitcoinTransactionViewModel
{
public string Token { get; set; }
public string WalletAddress { get; set; }
public BitcoinTransaction Transaction { get; set; }
}
public class BitcoinTransaction
{
public int Id { get; set; }
public BitcoinTransactionStatusTypes Status { get; set; }
public int TransactionId { get; set; }
public decimal Amount { get; set; }
public DateTime Time { get; set; }
public string Location { get; set; }
}
Любые идеи?
РЕДАКТИРОВАТЬ: Я понял это, в отмеченном ниже ответе...
Ответы
Ответ 1
Хорошо, я работал над чем-то другим, и бампандом в эту же проблему снова и снова.
Только на этот раз я понял, как это сделать!
Здесь ответ для всех, кто может быть заинтересован:
По-видимому, существует соглашение об именах. Обратите внимание:
Это не работает:
// Controller
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel transaction)
{
}
// View
@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { transaction = Model }))
{
@Html.HiddenFor(m => m.Token);
@Html.HiddenFor(m => m.Transaction.TransactionId);
.
.
Это работает:
// Controller
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel **RedeemTransaction**)
{
}
// View
@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { **RedeemTransaction** = Model }))
{
@Html.HiddenFor(m => m.Token);
@Html.HiddenFor(m => m.Transaction.TransactionId);
.
.
Другими словами - ошибка условного обозначения! Существовала неоднозначность именования между свойством Model.Transaction
и моим параметром формы transaction
+ контроллер. Unvelievable.
Если вы испытываете те же проблемы, убедитесь, что имя параметра вашего контроллера уникально - попробуйте переименовать его в MyTestParameter или что-то вроде этого...
Кроме того, если вы хотите отправить значения формы в контроллер, вам нужно будет включить их в скрытые поля, и вам будет хорошо.
Ответ 2
Подпись метода Send, который отправляет форма, имеет параметр с именем transaction, который, кажется, путает связующее устройство модели. Измените имя параметра как нечто не соответствующее имени свойства в вашей модели:
[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel model)
{
}
Кроме того, удалите параметр htmlAttributes из вашего вызова BeginForm, поскольку это не делает ничего полезного. Это будет:
@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post))
Любые данные, возвращаемые с клиента, могут быть изменены, поэтому вы должны отправлять только уникальный идентификатор транзакции, а затем извлекать любую дополнительную информацию об этом из своего источника данных для дальнейшей обработки. Вы также захотите проверить здесь, что пользователь, отправляющий данные, имеет доступ к указанному идентификатору транзакции, так как это могло быть также изменено.
Ответ 3
Это не зависит от MVC. Форма HTML будет отправлять только значения, содержащиеся в элементах формы внутри формы. Ваш пример не входит ни в форму, ни в элемент формы (например, скрытые входы). Вы должны это сделать, поскольку MVC не полагается на состояние просмотра. Поместите скрытые поля внутри в форму:
@Html.HiddenFor(x => x.Transaction.Time)
// etc...
Спросите себя, хотя.. если пользователь не обновляет эти значения.. требует ли ваш метод действий?
Ответ 4
Связывание модели гидратирует вашу модель представления в действии вашего контроллера через опубликованные значения формы. Я не вижу никаких элементов управления формы для ваших вышеупомянутых переменных, поэтому ничего не будет опубликовано назад. Вы видите, есть ли у вас такая радость?
@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post, new { transaction = Model }))
{
@Html.TextBoxFor(m => m.WalletAddress, new { placeholder = "Wallet Address", maxlength = "34" })
@Html.Hidden("Time", Model.Transaction.Time)
@Html.Hidden("Location", Model.Transaction.Location)
@Html.Hidden("TransactionId", Model.Transaction.TransactionId)
<input type="submit" value="Send" />
@Html.ValidationMessage("walletAddress", new { @class = "validation" })
}
Ответ 5
Попробуйте выполнить цикл с помощью следующего утверждения, а не с FOREACH
<table>
@for (var i = 0; i < Model.itemlist.Count; i++)
{
<tr>
<td>
@Html.HiddenFor(x => x.itemlist[i].Id)
@Html.HiddenFor(x => x.itemlist[i].Name)
@Html.DisplayFor(x => x.itemlist[i].Name)
</td>
</tr>
}
</table>
Ответ 6
Попробуйте создать коллекцию форм и получите значение as. Я думаю, что это может сработать.
public ActionResult Send(FormCollection frm)
{
var time = frm['Transaction.Time'];
}
Ответ 7
Поместите все поля внутри формы
@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post))
и убедитесь, что модель
BitcoinTransactionViewModel
включен или нет?
Ответ 8
Можете ли вы объединить те две модели, которые у вас есть? Здесь, как я делаю это с одной моделью на просмотр...
1. Я использую Display Templates из представления для просмотра, поэтому я могу передать всю модель, а также оставить данные зашифрованными.
2. Настройте свой основной вид следующим образом:
@model IEnumerable<LecExamRes.Models.SelectionModel.GroupModel>
<div id="container">
<div class="selectLabel">Select a Location:</div><br />
@foreach (var item in Model)
{
@Html.DisplayFor(model=>item)
}
</div>
3. Создайте папку DisplayTemplates в общей папке. Создайте представление, называя его, как ваша модель, которую вы хотите передать, потому что DisplayFor ищет шаблон отображения, названный в честь используемой вами модели, я вызываю свой GroupModel. Подумайте о шаблоне отображения в качестве экземпляра объекта вашего перечисления. Groupmodel Похоже, я просто назначаю группу кнопке.
@model LecExamRes.Models.SelectionModel.GroupModel
@using LecExamRes.Helpers
@using (Html.BeginForm("Index", "Home", null, FormMethod.Post))
{
<div class="mlink">
@Html.AntiForgeryToken()
@Html.EncryptedHiddenFor(model => model.GroupKey)
@Html.EncryptedHiddenFor(model => model.GroupName)
<p>
<input type="submit" name="gbtn" class="groovybutton" value=" @Model.GroupKey ">
</p>
</div>
}
4. Вот контроллер.
* GET и POST *
public ActionResult Index()
{
// Create a new Patron object upon user first visit to the page.
_patron = new Patron((WindowsIdentity)User.Identity);
Session["patron"] = _patron;
var lstGroups = new List<SelectionModel.GroupModel>();
var rMgr = new DataStoreManager.ResourceManager();
// GetResourceGroups will return an empty list if no resource groups where found.
var resGroups = rMgr.GetResourceGroups();
// Add the available resource groups to list.
foreach (var resource in resGroups)
{
var group = new SelectionModel.GroupModel();
rMgr.GetResourcesByGroup(resource.Key);
group.GroupName = resource.Value;
group.GroupKey = resource.Key;
lstGroups.Add(group);
}
return View(lstGroups);
}
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Index(SelectionModel.GroupModel item)
{
if (!ModelState.IsValid)
return View();
if (item.GroupKey != null && item.GroupName != null)
{
var rModel = new SelectionModel.ReserveModel
{
LocationKey = item.GroupKey,
Location = item.GroupName
};
Session["rModel"] = rModel;
}
//So now my date model will have Group info in session ready to use
return RedirectToAction("Date", "Home");
}
5. Теперь, если у меня есть много видов с различными моделями, я обычно использую модель, связанную с представлением, а затем с сеансом obj, который захватывает данные из каждой модели, поэтому в конце у меня есть данные для отправки.
Ответ 9
Название действия, которому будут отправляться данные, должно быть таким же, как имя действия, из которого данные отправляются. Единственное различие должно состоять в том, что второе действие, в котором должны быть отправлены данные, должно быть [HttpPost], а метод Posting должен обслуживать только запросы Get.