简体   繁体   English

MVC 4 ViewModel未被发送回Controller

[英]MVC 4 ViewModel not being sent back to Controller

I can't seem to figure out how to send back the entire ViewModel to the controller to the 'Validate and Save' function. 我似乎无法弄清楚如何将整个ViewModel发送回控制器到'验证和保存'功能。

Here is my controller: 这是我的控制器:

[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel transaction)
{
}

Here is the form in the view: 以下是视图中的表单:

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

When i click on submit, the conroller contains the correct value of the walletAddress field but transaction.Transaction.Time , transaction.Transaction.Location , transaction.Transaction.TransactionId are empty. 当我点击提交时,控制器包含walletAddress字段的正确值,但是transaction.Transaction.Timetransaction.Transaction.Locationtransaction.Transaction.TransactionId为空。

Is there a way i could pass the entire Model back to the controller? 有没有办法让整个模型传回控制器?

Edit: 编辑:

When i dont even receive the walletAddress in the controller. 当我甚至没有收到控制器中的walletAddress Everything gets nulled! 一切都变得无趣! When i remove this line alone: @Html.HiddenFor(m => m.Transaction.TransactionId); 当我单独删除这一行时: @Html.HiddenFor(m => m.Transaction.TransactionId); it works and i get the Token property on the controller, but when i add it back, all the properties of the transaction object on the controller are NULL. 它工作,我得到控制器上的Token属性,但当我添加回来时,控制器上的transaction对象的所有属性都是NULL。

Here is the BitcoinTransactionViewModel: 这是BitcoinTransactionViewModel:

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

Any ideas? 有任何想法吗?

EDIT: I figured it out, its in the marked answer below... 编辑:我想通了,它在下面的标记答案中......

OK, I've been working on something else and bumpend into the same issue all over again. 好吧,我一直在研究其他事情并再次陷入同样的​​问题。 Only this time I figured out how to make it work! 只是这次我想出了如何让它发挥作用!

Here's the answer for anyone who might be interested: 以下是可能感兴趣的人的答案:

Apparently, there is a naming convention. 显然,有一个命名约定。 Pay attention: 请注意:

This doesn't work: 这不起作用:

// 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);
.
.

This works: 这有效:

// 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);
.
.

In other words - a naming convention error! 换句话说 - 命名约定错误! There was a naming ambiguity between the Model.Transaction property and my transaction form field + controller parameter. Model.Transaction属性和我的transaction表单字段+ controller参数之间存在命名歧义。 Unvelievable. Unvelievable。

If you're experiencing the same problems make sure that your controller parameter name is unique - try renaming it to MyTestParameter or something like this... 如果您遇到相同的问题,请确保您的控制器参数名称是唯一的 - 尝试将其重命名为MyTestParameter或类似的东西......

In addition, if you want to send form values to the controller, you'll need to include them as hidden fields, and you're good to go. 此外,如果要将表单值发送到控制器,则需要将它们作为隐藏字段包含在内,并且您可以继续使用。

The signature of the Send method that the form is posting to has a parameter named transaction, which seems to be confusing the model binder. 表单发布到的Send方法的签名具有名为transaction的参数,这似乎使模型绑定器混乱。 Change the name of the parameter to be something not matching the name of a property on your model: 将参数的名称更改为与模型上的属性名称不匹配的内容:

[HttpPost]
public ActionResult Send(BitcoinTransactionViewModel model)
{
}

Also, remove the htmlAttributes parameter from your BeginForm call, since that's not doing anything useful. 另外,从BeginForm调用中删除htmlAttributes参数,因为它没有做任何有用的事情。 It becomes: 它成为了:

@using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post))

Any data coming back from the client could have been tampered with, so you should only post back the unique ID of the transaction and then retrieve any additional information about it from your data source to perform further processing. 从客户端返回的任何数据都可能已被篡改,因此您只应回发事务的唯一ID,然后从数据源检索有关它的任何其他信息以执行进一步处理。 You'll also want to verify here that the user posting the data has access to the specified transaction ID since that could've been tampered with as well. 您还需要在此验证发布数据的用户是否可以访问指定的事务ID,因为它也可能已被篡改。

This isn't MVC specific. 这不是MVC特定的。 The HTML form will only post values contained within form elements inside the form. HTML表单只会发布表单内表单元素中包含的值。 Your example is neither inside the form or in a form element (such as hidden inputs). 您的示例既不在表单内部也不在表单元素中(例如隐藏的输入)。 You have to do this since MVC doesn't rely on View State. 你必须这样做,因为MVC不依赖于View State。 Put hidden fields inside the form: 将隐藏字段放在表单中:

@Html.HiddenFor(x => x.Transaction.Time)
// etc...

Ask yourself though.. if the user isn't updating these values.. does your action method require them? 问问自己..如果用户没有更新这些值..你的行动方法是否需要它们?

Model binding hydrates your view model in your controller action via posted form values. 模型绑定通过已发布的表单值在控制器操作中对您的视图模型进行水合。 I don't see any form controls for your aforementioned variables, so nothing would get posted back. 我没有看到上述变量的任何表单控件,因此不会回发任何内容。 Can you see if you have any joy with this? 你能看出你对此有什么喜悦吗?

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

Try to loop with the folowing statement not with FOREACH 尝试循环使用下面的语句而不是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>

Try Form Collections and get the value as. 尝试表单集合并获取值。 I think this may work. 我认为这可行。

public ActionResult Send(FormCollection frm)
{
    var time = frm['Transaction.Time'];
}

Put all fields inside the form 将所有字段放在表单中

 @using (Html.BeginForm("Send", "DepositDetails", FormMethod.Post))

and make sure that the model 并确保模型

 BitcoinTransactionViewModel

included in view or not? 是否包含在视图中?

Can you just combine those 2 models you have? 你能把这两种型号合并吗? Here's how I do it with one model per view... 1. I use Display Templates from view to view so I can pass the whole model as well as leave data encrypted.. 2. Setup your main view like this... 以下是我每个视图使用一个模型的方法... 1.我使用视图中的显示模板进行查看,这样我就可以传递整个模型以及保留数据加密.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. Create a DisplayTemplates folder in shared. 3.在共享中创建DisplayTemplates文件夹。 Create a view, naming it like your model your want to pass because a DisplayFor looks for the display template named after the model your using, I call mine GroupModel. 创建一个视图,将其命名为您希望传递的模型,因为DisplayFor会查找以您使用的模型命名的显示模板,我称之为GroupModel。 Think of a display template as an object instance of your enumeration. 将显示模板视为枚举的对象实例。 Groupmodel Looks like this, I'm simply assigning a group to a button. 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. Here's the Controller. 这是控制器。 * GET & POST * * GET&POST *

public ActionResult Index()
    {
        // Create a new Patron object upon user's 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. Now if I've got alot of Views with different models, I typically use a model related to the view and then a session obj that grabs data from each model so in the end I've got data to submit. 5.现在,如果我有很多不同模型的视图,我通常使用与视图相关的模型,然后使用会话obj从每个模型中获取数据,所以最后我有数据要提交。

The action name to which the data will be posted should be same as the name of the action from which the data is being posted. 要将数据发布到的操作名称应与从中发布数据的操作名称相同。 The only difference should be that the second action where the data is bein posted should have [HttpPost] and the Posting method should serve only Get requests. 唯一的区别应该是发布数据的第二个操作应该有[HttpPost],而Posting方法应该只提供Get请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM