C# MVC 4 ViewModel 没有被发送回控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18299669/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:51:11  来源:igfitidea点击:

MVC 4 ViewModel not being sent back to Controller

c#asp.net-mvcasp.net-mvc-4

提问by Uri Abramson

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.TransactionIdare 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 walletAddressin the controller. Everything gets nulled! When i remove this line alone: @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 transactionobject on the controller are NULL.

当我什至没有walletAddress在控制器中收到时。一切都归零了!当我单独删除这一行时:@Html.HiddenFor(m => m.Transaction.TransactionId);它起作用并且我在控制器上获得了 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...

编辑:我想通了,它在下面的标记答案中......

采纳答案by Uri Abramson

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.Transactionproperty and my transactionform field + controller parameter. Unvelievable.

换句话说 - 命名约定错误!Model.Transaction属性和我的transaction表单字段 + 控制器参数之间存在命名歧义。难以置信。

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.

此外,如果您想将表单值发送到控制器,您需要将它们作为隐藏字段包含在内,这样就可以了。

回答by Simon Whitehead

This isn't MVC specific. The HTML form will only post values contained within form elements inside the form. 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. Put hidden fields insidethe form:

这不是 MVC 特定的。HTML 表单只会发布包含在表单内的表单元素中的值。您的示例既不在表单内,也不在表单元素(例如隐藏输入)中。您必须这样做,因为 MVC 不依赖于视图状态。将隐藏字段放入表单中:

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

Ask yourself though.. if the user isn't updating these values.. does your action method require them?

问问自己……如果用户没有更新这些值……您的操作方法是否需要它们?

回答by Mister Epic

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

回答by Jonathan Little

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. Change the name of the parameter to be something not matching the name of a property on your model:

表单发送到的 Send 方法的签名有一个名为 transaction 的参数,这似乎混淆了模型绑定器。将参数名称更改为与模型上的属性名称不匹配的名称:

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

Also, remove the htmlAttributes parameter from your BeginForm call, since that's not doing anything useful. It becomes:

此外,从您的 BeginForm 调用中删除 htmlAttributes 参数,因为这没有任何用处。它成为了:

@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. 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,然后从数据源检索有关它的任何其他信息以执行进一步处理。您还需要在此处验证发布数据的用户是否有权访问指定的交易 ID,因为该 ID 也可能被篡改。

回答by Kalyan

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?

是否包含在视图中?

回答by foxtrotZulu

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. 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. 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.

3. 在 shared 中创建一个 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. Here's the Controller. *GET & POST *

4. 这是控制器。 *获取和发布 *

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,因此最后我有数据要提交。

回答by Nowshath

Try Form Collections and get the value as. I think this may work.

尝试表单集合并获取值。我认为这可能奏效。

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

回答by Valynk

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>

回答by Bounty

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 请求。