在我的MVC应用程序中,我有一个类似于此的View Model:
public class ComplexViewModel
{
public ComplexDetailsViewModel Details1 { get; set; }
public ComplexDetailsViewModel Details2 { get; set; }
}
public class ComplexDetailsViewModel
{
public int Id { get; set; }
public string DisplayValue1 { get; set; }
public string DisplayValue2 { get; set; }
// ...
}
我原本在以下视图中执行以下操作:
@Html.HiddenFor(model => model.Details1.Id)
@Html.HiddenFor(model => model.Details2.Id)
@Html.DisplayFor(model => model.Details1.DisplayValue1)
...
我会将完整模型发布到控制器:
public ActionResult Post(ComplexViewModel model)
除了Id值之外,我实际上并不需要ComplexViewModel中的任何内容,因此我决定创建另一个专门用于POST数据的视图模型:
public class PostViewModel
{
public int Details1Id { get; set; }
public int Details2Id { get; set; }
}
public ActionResult Post(PostViewModel model)
问题是现在我的@HiddenFor(model => model.Details1.Id)
没有映射到我的POST模型,因此实际上没有任何内容被发布。
在使用HiddenFor
助手时,有没有办法为我的POST模型和我的GET模型提供单独的结构?
答案 0 :(得分:5)
仅仅因为你没有使用POST版本中的所有数据并不意味着你必须制作另一个模型。为什么不保持简单?
这是它应该如何运作的:
您的帖子详细信息视图应该是对特定视图模型的强类型。然后在您的控制器中,您有两个名为Post的操作结果,例如,一个用[HTTPGET]
属性修饰,您要发布到的操作用[HTTPPOST]
属性修饰。此外,您的get方法应该使用诸如post id之类的参数,并且post方法应该将模型作为参数。
要正确执行服务器端验证,您可以像这样装饰类属性:
public class ComplexDetailsViewModel
{
[Required]//Works for just the Id property
public int Id { get; set; }
public string DisplayValue1 { get; set; }
public string DisplayValue2 { get; set; }
// ...
}
现在在你的控制器中你可以使用这个bool:ModelState.IsValid
。基本上,如果他们关闭了JavaScript并且模型发布时没有Id
,那么该模型将无效。
这种模式非常强大,可以快速实现客户端和服务器端验证。当然,客户端验证使用开箱即用的jQuery,因此我们可以轻松扩展验证器。您甚至可以非常快速地进行AJAX验证。当我构建我的表单时,我不会在验证时牺牲任何地方......因为它不需要时间来正确地完成它。
回答您的原始问题:
视图只能强类型化为一个模型。您无法使用一个模型加载视图,并将其与另一个模型一起发布(据我所知)。我想如果你想要这样做,你的问题就在于你建立模型的方式。
答案 1 :(得分:1)
只需手动编写隐藏输入的HTML,而不是使用Html Helpers。
<input type="hidden" id="Details1Id" value="@Model.Details1.Id"/>
<input type="hidden" id="Details2Id" value="@Model.Details1.Id"/>
<强>更新强>
我在做类似事情时遇到了问题。我最终在视图中展平了与表单相关的属性。 Automapper使得从其他对象映射到您的视图变得非常容易,并且可以使层次结构变得扁平化。这样做,您的新视图可能最终看起来与此类似。
public class ComplexViewModel
{
public long Details1Id { get; set; }
public string Details1Name { get; set; }
public long Details2Id { get; set; }
public string Details2Name { get; set; }
}
答案 2 :(得分:1)
模型需要更相似。一个“视图”模型具有类属性,而“后”模型则没有。如果类属性的名称和属性不匹配,则它们不受模型绑定器的约束。尝试类似:
public class ComplexViewModel
{
public ComplexDetailsViewModel Details1 { get; set; }
public ComplexDetailsViewModel Details2 { get; set; }
}
public class ComplexDetailsViewModel : PostDetailsModel
{
public string DisplayValue1 { get; set; }
public string DisplayValue2 { get; set; }
}
public class PostModel
{
public PostDetailsModel Details1 { get; set; }
public PostDetailsModel Details2 { get; set; }
}
public class PostDetailsModel
{
public int Id { get; set; }
}
View
和Post
之间不使用相同模型的大问题是验证。如果要更改验证会发生什么(假设使用客户端和服务器端的内置MVC验证)。现在你必须改变两个模型!哦等等......不,你没有......
public interface MyValidation
{
[required]
public int id { get; set; }
}
然后只需将这些验证添加到您的类中: (MetadataType告诉MVC用于验证的内容)
[MetadataType(typeof(MyValidation))]
public class ComplexDetailsViewModel ....
[MetadataType(typeof(MyValidation))]
public class PostDetailsModel ....
这当然可行,但我强烈建议不要让任何人在视图和回发之间使用两种不同的模型。在这种情况下,我完全没有理由认为它们应该是不同的。
答案 3 :(得分:0)
简单:只需让您的视图的视图模型继承自控制器后模型。然后你的HiddenFor方法有工作,你只需要确保你期望发布的属性在基类(post模型)中。