在属性上放置简单的数据注释很棒,
public class UnicornViewModel
{
[Required]
public string Name { get; set; }
但是我要说我有这样的事情:
public class SuperPower
{
public class Name { get; set; }
}
public class UnicornViewModel
{
[Required]
public string Name { get; set; }
public SuperPower PrimarySuperPower { get; set; }
public SuperPower SecondarySuperPower { get; set; }
如何在PrimarySuperPower.Name上应用Required属性,同时为SecondarySuperPower.Name保留可选属性?最好是1.与客户端验证相关的东西,2。没有任何特殊处理,比如在Action / Custom验证器中检查PrimarySuperPower.Name的值,如果它是空的,则添加ModelState错误。如果有类似的话会很棒:
[Required(p => p.Name)]
public SuperPower PrimarySuperPower { get; set; }
public SuperPower SecondarySuperPower { get; set; }
答案 0 :(得分:1)
通常不支持:ASP.NET MVC3 Validation of nested view model object fields
但是你可以实现自定义模型验证,但是对于客户端和服务器端这样做会变得相当复杂。
如果您有自己的SuperPower对象模板,它可以查找您自己的属性:
[RequiredSubProperty("Name")]
public SuperPower PrimarySuperPower { get; set; }
在模板中,刚刚通过不显眼的验证属性进入TextBoxFor的htmlAttributes参数或您使用的任何输入助手。
如果您没有使用模板,我会放弃所有这些,只是在显示名字时将不显眼的验证属性传递给htmlAttributes参数,而不是第二个名称。
另一种选择是将UnicornViewModel展平为像
public class UnicornViewModel
{
[Required]
public string Name { get; set; }
[Required]
public string PrimarySuperPowerName { get; set; }
public string SecondarySuperPowerName { get; set; }
这完全取决于您可以从更复杂的方法中获得多少重用。当我尝试使用模板很多时,我发现在不同的上下文中,某些关于模板的事情没有意义,而且我需要在对象模板上有很多变化(当父模板上显示子模板时,它没有意义让孩子有一个链接到父母细节的URL,因为你已经在那个页面上,但是在其他地方使用了儿童模板,它应该显示到父母的链接)。最终我停止使用模板,并偶尔使用部分,其中有很多重用的好例子。用户界面是橡胶与道路相遇的地方,而ViewModels的结构与实体/商业模式不同。
答案 1 :(得分:0)
您无法使用标准数据属性执行此操作。您提到的必需语法在自定义实现中是不可能的,因为没有引用您尝试使用lambda的对象。
您可能最好使用第三方验证库,例如FluentValidation。它为您的验证要求提供了相当大的灵活性。
答案 2 :(得分:0)
我个人非常喜欢使用ModelMetadataClass来管理我的ViewModel。如果您愿意继续使用AutoMapper,可以创建一个viewmodel,如下所示:
public class SuperPower
{
public string Name { get; set; }
}
[MetadataType(typeof(UnicornViewModel.UnicornViewModelMetaData))]
public class UnicornViewModel
{
public string Name { get; set; }
public RequiredSuperPowerViewModel PrimarySuperPower { get; set; }
public SuperPower SecondarySuperPower { get; set; }
public class UnicornViewModelMetaData
{
[Required]
public string Name { get; set; }
}
}
[MetadataType(typeof(UnicornViewModel.UnicornViewModelMetaData))]
public class RequiredSuperPowerViewModel : SuperPower
{
public class RequiredSuperPowerModelMetaData
{
[Required]
public string Name { get; set; }
}
}
这将允许您选择您希望给定模型类所需的字段,而不会影响您的模型。
如果您使用的是AutoMapper,可按如下方式对原始SuperPower进行补水:
SuperPower reqSuperPower = AutoMapper.Mapper.Map<RequiredSuperPowerViewModel, SuperPower>(Data.PrimarySuperPower);
答案 3 :(得分:0)
这可能是一个迟到的答案,但我在寻找同样的事情时发现了这个问题。 这就是我解决我的特殊情况的方法:
在我这之前:
public class ProductVm
{
//+ some other properties
public Category Category {get; set;}
public Category ParentCategory {get; set;}
}
我想在其中拥有以下内容:
public class ProductVm
{
//some other properties
[DisplayName("Product Category", e => e.Description)]
public Category Category {get; set;}
[DisplayName("Parent Category", e => e.Description)]
public Category ParentCategory {get; set;}
}
我无法在模型中输入它,因为两者都是同一个对象类。
我这样解决了(因为在这种情况下我只需要读取描述值而不是写它):
public class ProductVm
{
//some other properties
public Category Category {get; set;}
public Category ParentCategory {get; set;}
[DisplayName("Product Category")]
public string Category => Category.Description;
[DisplayName("Main Category")]
public string ParentCategory => ParentCategory.Description;
}
您可以稍微重写一下以保留剩余的私有支持字段并删除Category对象的属性封装,但在我的情况下,我仍然需要将它们公开用于其他用途。
关于上述问题,我会做以下事情:
public class UnicornViewModel
{
[Required]
public string Name { get; set; }
public SuperPower PrimarySuperPower { get; set; }
public SuperPower SecondarySuperPower { get; set; }
[Required]
public string PrimarySuperPowerName
{
get { return PrimarySuperPower.Name; }
set { PrimarySuperPower.Name = value; }
}
public string SecondarySuperPowerName
{
get { return SecondarySuperPower.Name; }
set { SecondarySuperPower.Name = value; }
}
}
然后我将我的View绑定到字符串属性并排除SuperPower属性。