Need help using the DefaultModelBinder for a nested model

…衆ロ難τιáo~ 提交于 2019-12-12 16:15:39

问题


There are a few related questions, but I can't find an answer that works.

Assuming I have the following models:

public class EditorViewModel
{
  public Account Account {get;set;}
  public string SomeSimpleStuff {get;set;}
}

public class Account
{
  public string AccountName {get;set;}
  public int MorePrimitivesFollow {get;set;}
}

and a view that extends ViewPage<EditorViewModel> which does the following:

<%= Html.TextBoxFor(model => model.Account.AccountName)%>
<%= Html.ValidationMessageFor(model => model.Account.AccountName)%>
<%= Html.TextBoxFor(model => model.SomeSimpleStuff )%>
<%= Html.ValidationMessageFor(model => model.SomeSimpleStuff )%>

and my controller looks like:

[HttpPost]
public virtual ActionResult Edit(EditorViewModel account)
{ /*...*/ }

How can I get the DefaultModelBinder to properly bind my EditorViewModel? Without doing anything special, I get an empty instance of my EditorViewModel with everything null or default.

The closest I've come is by calling UpdateModel manually:

[HttpPost]
public virtual ActionResult Edit(EditorViewModel account)
{
    account.Account = new Account();
    UpdateModel(account.Account, "Account");
    // this kills me:
    UpdateModel(account);

This successfully updates my Account property model, but when I call UpdateModel on account (to get the rest of the public properties of my EditorViewModel) I get the completely unhelpful "The model of type ... could not be updated." There is no inner exception, so I can't figure out what's going wrong.

What should I do with this?


回答1:


The binder is getting confused because it sees that the parameter to your action method is named account, and it sees incoming form fields named account.accountname, so it's looking for an AccountName property on your EditorViewModel.

You can fix this by renaming the parameter to something else that doesn't conflict with an incoming form field, or you can stick an [Bind(Prefix = "")] attribute on the parameter. This attribute says "ignore the fact that the parameter is named account, and pretend I had given it an empty string name instead." Then the binder will look for account.accountname instead of account.account.accountname.

Edit - further info:

When the binder sees a complex parameter named foo, it looks at the current request for anything named *foo.**. So if your parameter were named foo and its type had a property named FirstName, the incoming value would be expected to be foo.FirstName=John, for example.

However, if the binder does not see a *foo.** as part of the request, it just looks for the * directly (without the foo prefix). So as long as there wasn't a *foo.** present in the request, you could submit FirstName=John and the binder would understand this correctly. But if there is any *foo.** as part of the request, the FirstName=John value will not match the FirstName property.

You can see now how giving the parameter to your action method the same name as one of its properties would throw off this logic.



来源:https://stackoverflow.com/questions/2563685/need-help-using-the-defaultmodelbinder-for-a-nested-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!