复杂对象和模型绑定器 ASP.NET MVC
Complex object and model binder ASP.NET MVC
我有一个带有 Foo
class 的模型对象结构,其中包含一个带有字符串值的 Bar
。
public class Foo
{
public Bar Bar;
}
public class Bar
{
public string Value { get; set; }
}
以及像这样使用该结构的视图模型
public class HomeModel
{
public Foo Foo;
}
然后我有一个表单,在 Razor 中看起来像这样。
<body>
<div>
@using (Html.BeginForm("Save", "Home", FormMethod.Post))
{
<fieldset>
@Html.TextBoxFor(m => m.Foo.Bar.Value)
<input type="submit" value="Send"/>
</fieldset>
}
</div>
</body>
在html中变成。
<form action="/Home/Save" method="post">
<fieldset>
<input id="Foo_Bar_Value" name="Foo.Bar.Value" type="text" value="Test">
<input type="submit" value="Send">
</fieldset>
</form>
控制器终于可以像这样处理 post 厕所了
[HttpPost]
public ActionResult Save(Foo foo)
{
// Magic happends here
return RedirectToAction("Index");
}
我的问题是 Foo
中的 Bar
一旦遇到 Save
控制器操作(Foo
已创建但带有 null
Bar
字段).
我认为 MVC 中的模型绑定器可以创建 Foo
和 Bar
对象并设置 Value
属性,只要它看起来像以上。我错过了什么?
我也知道我的视图模型有点过于复杂并且可以更简单,但是对于我正在尝试做的事情,如果我可以使用更深层次的对象结构,我真的会帮助我。上面的例子使用 ASP.NET 5.
首先,DefaultModelBinder
不会绑定到字段,因此您需要使用属性
public class HomeModel
{
public Foo Foo { get; set; }
}
其次,助手正在生成基于 HomeModel
的控件,但您回发到 Foo
。将 POST 方法更改为
[HttpPost]
public ActionResult Save(HomeModel model)
或使用 BindAttribute
来指定 Prefix
(这实质上是从发布的值中剥离前缀的值 - 所以 Foo.Bar.Value
变成 Bar.Value
绑定)
[HttpPost]
public ActionResult Save([Bind(Prefix="Foo")]Foo model)
另请注意,您不应将方法参数命名为与您的某个属性同名,否则绑定将失败并且您的模型将为空。
我刚刚发现发生这种情况的另一个原因,那就是如果您的 属性 被命名为 Settings
!考虑以下视图模型:
public class SomeVM
{
public SomeSettings DSettings { get; set; } // named this way it will work
public SomeSettings Settings { get; set; } // property named 'Settings' won't bind!
public bool ResetToDefault { get; set; }
}
在代码中,如果您绑定到 Settings
属性,它将无法绑定(不仅在 post 上,甚至在生成表单时也是如此)。如果您将 Settings
重命名为 DSettings
(等等),它突然又可以工作了。
我遇到了同样的问题,在我按照@Stephen Muecke 的步骤进行操作后,我意识到问题是因为我的输入被禁用了(我在准备好文档时使用 JQuery 禁用了它们),如您所见这里:How do I submit disabled input in ASP.NET MVC?。最后我使用只读而不是禁用属性,所有值都成功发送到控制器。
我遇到了同样的问题,但是一旦我为外键创建了一个隐藏字段...一切正常...
表格示例:
@using (Html.BeginForm("save", "meter", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => Model.Entity.Id)
@Html.HiddenFor(model => Model.Entity.DifferentialMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.LinearMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.GatheringMeter.MeterId)
... all your awesome controls go here ...
}
动作示例:
// POST: /Meter/Save
[HttpPost]
public ActionResult Save(Meter entity)
{
... world-saving & amazing logic goes here ...
}
美图:
我有一个带有 Foo
class 的模型对象结构,其中包含一个带有字符串值的 Bar
。
public class Foo
{
public Bar Bar;
}
public class Bar
{
public string Value { get; set; }
}
以及像这样使用该结构的视图模型
public class HomeModel
{
public Foo Foo;
}
然后我有一个表单,在 Razor 中看起来像这样。
<body>
<div>
@using (Html.BeginForm("Save", "Home", FormMethod.Post))
{
<fieldset>
@Html.TextBoxFor(m => m.Foo.Bar.Value)
<input type="submit" value="Send"/>
</fieldset>
}
</div>
</body>
在html中变成。
<form action="/Home/Save" method="post">
<fieldset>
<input id="Foo_Bar_Value" name="Foo.Bar.Value" type="text" value="Test">
<input type="submit" value="Send">
</fieldset>
</form>
控制器终于可以像这样处理 post 厕所了
[HttpPost]
public ActionResult Save(Foo foo)
{
// Magic happends here
return RedirectToAction("Index");
}
我的问题是 Foo
中的 Bar
一旦遇到 Save
控制器操作(Foo
已创建但带有 null
Bar
字段).
我认为 MVC 中的模型绑定器可以创建 Foo
和 Bar
对象并设置 Value
属性,只要它看起来像以上。我错过了什么?
我也知道我的视图模型有点过于复杂并且可以更简单,但是对于我正在尝试做的事情,如果我可以使用更深层次的对象结构,我真的会帮助我。上面的例子使用 ASP.NET 5.
首先,DefaultModelBinder
不会绑定到字段,因此您需要使用属性
public class HomeModel
{
public Foo Foo { get; set; }
}
其次,助手正在生成基于 HomeModel
的控件,但您回发到 Foo
。将 POST 方法更改为
[HttpPost]
public ActionResult Save(HomeModel model)
或使用 BindAttribute
来指定 Prefix
(这实质上是从发布的值中剥离前缀的值 - 所以 Foo.Bar.Value
变成 Bar.Value
绑定)
[HttpPost]
public ActionResult Save([Bind(Prefix="Foo")]Foo model)
另请注意,您不应将方法参数命名为与您的某个属性同名,否则绑定将失败并且您的模型将为空。
我刚刚发现发生这种情况的另一个原因,那就是如果您的 属性 被命名为 Settings
!考虑以下视图模型:
public class SomeVM
{
public SomeSettings DSettings { get; set; } // named this way it will work
public SomeSettings Settings { get; set; } // property named 'Settings' won't bind!
public bool ResetToDefault { get; set; }
}
在代码中,如果您绑定到 Settings
属性,它将无法绑定(不仅在 post 上,甚至在生成表单时也是如此)。如果您将 Settings
重命名为 DSettings
(等等),它突然又可以工作了。
我遇到了同样的问题,在我按照@Stephen Muecke 的步骤进行操作后,我意识到问题是因为我的输入被禁用了(我在准备好文档时使用 JQuery 禁用了它们),如您所见这里:How do I submit disabled input in ASP.NET MVC?。最后我使用只读而不是禁用属性,所有值都成功发送到控制器。
我遇到了同样的问题,但是一旦我为外键创建了一个隐藏字段...一切正常...
表格示例:
@using (Html.BeginForm("save", "meter", FormMethod.Post))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => Model.Entity.Id)
@Html.HiddenFor(model => Model.Entity.DifferentialMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.LinearMeter.MeterId)
@Html.HiddenFor(model => Model.Entity.GatheringMeter.MeterId)
... all your awesome controls go here ...
}
动作示例:
// POST: /Meter/Save
[HttpPost]
public ActionResult Save(Meter entity)
{
... world-saving & amazing logic goes here ...
}
美图: