Подтвердить что ты не робот

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

Любые идеи?

РЕДАКТИРОВАТЬ: Я понял это, в отмеченном ниже ответе...

4b9b3361

Ответ 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.