ASP.net MVC – 用于POST操作的单独ViewModel
在我的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模型,因此实际上没有任何内容被POST。
有没有办法为我的POST模型和我的GET模型提供单独的结构,同时仍然使用HiddenFor
帮助器?
只需手动编写隐藏输入的HTML而不是使用Html Helpers。
更新
我做了类似的事情。 我最终在视图中展平了与表单相关的属性。 Automapper使得从其他对象映射到视图变得非常容易,并且可以使层次结构变得扁平化。 这样做,您的新视图可能最终看起来与此类似。
public class ComplexViewModel { public long Details1Id { get; set; } public string Details1Name { get; set; } public long Details2Id { get; set; } public string Details2Name { get; set; } }
仅仅因为你不使用POST版本中的所有数据并不意味着你必须制作另一个模型。 为什么不保持简单?
这是它应该如何工作:
您的post详细信息视图应该是针对特定视图模型的强类型。 然后在你的控制器中你有两个名为Post的动作结果,例如,一个用[HTTPPOST]
属性修饰,你要发布的动作用[HTTPPOST]
属性[HTTPPOST]
。 此外,您的get方法应该使用诸如post id之类的参数,并且post方法应该将模型作为参数。
要正确执行服务器端validation,您可以像这样装饰类属性:
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
那么该模型将无效。
这种模式非常强大,可以快速实现客户端和服务器端validation。 当然,客户端validation使用开箱即用的jQuery,因此我们可以轻松扩展validation器。 您甚至可以非常快速地进行AJAXvalidation。 当我构建表单时,在validation时我不会牺牲任何地方。因为它不需要时间来正确地完成它。
要回答您的原始问题:
视图只能强类型化为一个模型。 您无法使用一个模型加载视图,并将其与另一个模型一起发布(据我所知)。 我想如果你想要这样做,你的问题就在于你建立模型的方式。
模型需要更相似。 一个“视图”模型具有类属性,而“后”模型则没有。 如果类属性的名称和属性不匹配,则它们不受模型绑定器的约束。 尝试以下方法:
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
之间不使用相同模型的大问题是validation。 如果要更改validation会发生什么(假设使用客户端和服务器端的内置MVCvalidation)。 现在你必须改变两个模型! 哦等等……不,你不…
public interface MyValidation { [required] public int id { get; set; } }
然后只需将这些validation添加到您的类中:( MetadataType告诉MVC用于validation的内容)
[MetadataType(typeof(MyValidation))] public class ComplexDetailsViewModel .... [MetadataType(typeof(MyValidation))] public class PostDetailsModel ....
这肯定会奏效,但我强烈建议任何人不要在视图和回发之间使用两种不同的模型。 在这种情况下,我完全没有理由认为它们应该是不同的。
简单:只需让您的视图的视图模型inheritance您的控制器后模型。 然后你的HiddenFor方法有了工作,你只需要确保你期望发布的属性在基类(post模型)中。