【问题标题】:Is there a way to reuse data annotations?有没有办法重用数据注释?
【发布时间】:2013-11-13 18:34:47
【问题描述】:

有没有办法在 ASP.Net MVC 4 的视图中用作模型的类内部实现数据域(在属性级别)的想法?

考虑这段代码:

public class LoginProfileModel {

    [DisplayName("Login ID")]
    [Required(ErrorMessage = "Login ID is required.")]
    public string LogonID { get; set; }

    [DisplayName("Password")]
    [Required(ErrorMessage = "Password cannot be blank.")]
    [StringLength(20, MinimumLength = 3)]
    [DataType(DataType.Password)]
    public string Password { get; set; }
}

这是 ASP.Net MVC 4 中的 LoginProfileModel。它使用各种元数据/数据注释,以便我可以使用以下代码创建干净的视图:

@model myWebSite.Areas.People.Models.LoginProfileModel

@using ( Html.BeginForm( "Index" , "Login" ) ) {
    @Html.ValidationSummary()
    @Html.EditorForModel()
    <input type="submit" value="Login" />
}

我在多个视图中使用“登录 ID”和“密码”的概念,因此,在多个视图模型中。我希望能够定义密码使用的属性,或者可能是密码本身及其所有数据注释在一个位置,以便我可以在需要时重用所有这些定义,而不是每次使用时都重新指定它们:

    [DisplayName("Password")]
    [Required(ErrorMessage = "Password cannot be blank.")]
    [StringLength(20, MinimumLength = 3)]
    [DataType(DataType.Password)]
    public string Password { get; set; }

这有可能吗?

【问题讨论】:

    标签: c# asp.net-mvc viewmodel data-annotations code-reuse


    【解决方案1】:

    以下属性会影响 View 的验证过程。

    [Required(ErrorMessage = "Password cannot be blank.")]
    [StringLength(20, MinimumLength = 3)]
    

    对于 Validation 属性,您可以像这样创建一个类:

    public class PasswordRuleAttribute : ValidationAttribute
        {    
            public override bool IsValid(object value)
            {
    
                if (new RequiredAttribute { ErrorMessage = "Password cannot be blank." }.IsValid(value) && new StringLengthAttribute(20) { MinimumLength=3 }.IsValid(value) )
                    return true;
    
                return false;
            }
        }
    

    您可以按如下方式使用它:

    [PasswordRule]
    public string Password{get;set;}
    

    您提到的其他两个属性直接派生自Attribute 类,我认为没有办法将它们合并为一个属性。

    我会尽快为您更新。

    所以现在我们只剩下:

    [DisplayName("Password")]
    [DataType(DataType.Password)]
    [PasswordRule]
    public string Password{get;set;}
    

    编辑:

    根据这篇帖子:Composite Attribute,无法合并属性。

    【讨论】:

    • 在戳了一会儿后将其标记为最佳答案。它允许我集中验证逻辑,这最终是我所追求的。
    • 分离字段验证的好主意。如果我们能有一个可重复使用的[DisplayName] 技术,那就太好了。
    【解决方案2】:

    您可以使用伙伴类来执行此操作,该类为您的视图模型提供元数据。像这样:

    public partial class LogonMetaData
    {
        [DisplayName("Login ID")]
        [Required(ErrorMessage = "Login ID is required.")]
        public string LogonID { get; set; }
    
        [DisplayName("Password")]
        [Required(ErrorMessage = "Password cannot be blank.")]
        [StringLength(20, MinimumLength = 3)]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }
    

    那么你的视图模型:

    using System.ComponentModel.DataAnnotations;
    
    [MetadataType(typeof(LogonMetaData))]
    public partial class FirstViewModel
    {
        public string LogonID { get; set; }
        public string Password { get; set; }
    }
    
    using System.ComponentModel.DataAnnotations;
    
    [MetadataType(typeof(LogonMetaData))]
    public partial class SecondViewModel
    {
        public string LogonID { get; set; }
        public string Password { get; set; }
    }
    

    注意在类定义中使用partial。这就是允许这种方法起作用的原因。一个警告,除了 DRY 的明显问题之外,我认为元数据类必须与您的视图模型位于同一命名空间中,否则它会抱怨。除此之外,这应该可以满足您的需求。

    【讨论】:

      【解决方案3】:

      作为 John H 回答的推论,您可以只使用继承并使那些具有“LogonId 和密码的想法”的视图模型从该基本视图模型继承。这将解决上一个答案中提到的元数据问题。

            public class LoginProfileModel {
      
              [DisplayName("Login ID")]
              [Required(ErrorMessage = "Login ID is required.")]
              public string LogonID { get; set; }
      
              [DisplayName("Password")]
              [Required(ErrorMessage = "Password cannot be blank.")]
              [StringLength(20, MinimumLength = 3)]
              [DataType(DataType.Password)]
              public string Password { get; set; }
          }
      
          public SomeOtherClassThatNeedsLoginInfo : LoginProfileModel{
      
               public string Property {get;set;}
      }
      

      现在在 SomeOtherClassThatNeedsLoginInfo 中,您可以使用这些属性及其相关的 DataAnnotations。

      另一个想法是将 LoginInfo 作为属性传递给您的其他视图模型。

      public SomeOtherClassThatNeedsLoginInfo{
      
                   public string Property {get;set;}
      
                   public LoginProfileModel LoginModel {get;set;}
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        • 2013-04-26
        相关资源
        最近更新 更多