Is there a way to reuse data annotations?

戏子无情 提交于 2019-12-04 14:44:13
gldraphael

The following attributes affect the validation process of your View.

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

For the Validation attributes, you can create a class like this:

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

You can use it as follows:

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

The other two attributes that you mentioned are Directly derived from the Attribute class, and I don't think there's a way to consolidate them into a single attribute.

I'll update you with an edit soon.

So now we're left with:

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

EDIT:

According to this post: Composite Attribute, it's not possible to merge attributes.

You can do this using a buddy class, which provides metadata for your view model. Like so:

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

Then your view models:

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

Note the use of partial in the class definitions. This is what allows this approach to work. One caveat, other than the obvious problem with DRY, is that I believe the metadata class has to reside in the same namespace as your view models, else it complains. Other than that, this should do what you want.

As a corollary to John H's answer, you could just use inheritance and make those view models that have the "idea of a LogonId and password" inherit from that base view model. This would solve the MetaData issues that were mentioned in the previous answer.

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

Now in the SomeOtherClassThatNeedsLoginInfo, those properties and their related DataAnnotations will be available to you.

Another idea would be just to pass that LoginInfo as a property on your other view models.

public SomeOtherClassThatNeedsLoginInfo{

             public string Property {get;set;}

             public LoginProfileModel LoginModel {get;set;}
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!