9

将简单的数据注释放在属性上很棒,

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; }
4

4 回答 4

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 是没有意义的,因为您已经在该页面上,但是在使用子模板的其他任何地方,它都应该显示该链接到父母)。最终我停止使用模板,偶尔在有很多重用情况的情况下使用部分模板。UI 是橡胶与道路相遇的地方,ViewModel 的结构不会像您的实体/业务模型那样好。

于 2013-06-17T17:50:50.547 回答
1

这可能是一个迟到的答案,但我在搜索同样的东西时发现了这个问题。这就是我解决我的特殊情况的方法:

在我有这个之前:

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; }
    }
}

然后我将我的视图绑定到字符串属性并排除 SuperPower 属性。

于 2017-06-07T21:59:33.837 回答
0

I, personally, am a fan of using the ModelMetadataClass to directorate my ViewModels. If you are willing to go on step extra and use AutoMapper you could create a viewmodel as follows:

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; }

    }
}

This will allow you to pick which fields you would like required for a given model class without impacting your model.

If you are using AutoMapper you can rehydrate the original SuperPower as follows:

SuperPower reqSuperPower = AutoMapper.Mapper.Map<RequiredSuperPowerViewModel, SuperPower>(Data.PrimarySuperPower);
于 2013-06-23T15:20:41.973 回答
0

您无法使用标准数据属性执行此操作。您提到的必需语法在自定义实现中也不可能,因为没有对您尝试使用 lambda 的对象的引用。

您最好使用第三方验证库,例如 FluentValidation。它为您的验证要求提供了相当大的灵活性。

于 2013-06-17T18:30:14.470 回答