Search code examples
c#asp.netasp.net-mvcdata-annotationsvalidationattribute

Get Data Annotations attributes from model


I want to create custom client-side validator, but I want define validation rules via Data Annotations attributes at business logic layer. How can I access model validation attributes in runtime?

I want to write 'generator', which will convert this code:

public class LoginModel
{
    [Required]
    [MinLength(3)]
    public string UserName { get; set; }

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

into this one:

var loginViewModel= {
    UserName: ko.observable().extend({ minLength: 3, required: true }),
    Password: ko.observable().extend({ required: true })
};

But not from .cs sources, of course. =)

Maybe reflection?

UPD

I've found this method: MSDN. But can't understand how to use it.


Solution

  • This is the universal way how to do this:

    private string GenerateValidationModel<T>()
    {
        var name = typeof(T).Name.Replace("Model", "ViewModel");
        name = Char.ToLowerInvariant(name[0]) + name.Substring(1);
    
        var validationModel = "var " + name + " = {\n";
    
        foreach (var prop in typeof(T).GetProperties())
        {
            object[] attrs = prop.GetCustomAttributes(true);
            if (attrs == null || attrs.Length == 0)
                continue;
    
            string conds = "";
    
            foreach (Attribute attr in attrs)
            {
                if (attr is MinLengthAttribute)
                {
                    conds += ", minLength: " + (attr as MinLengthAttribute).Length;
                }
                else if (attr is RequiredAttribute)
                {
                    conds += ", required: true";
                }
                // ...
            }
    
            if (conds.Length > 0)
                validationModel += String.Format("\t{0}: ko.observable().extend({{ {1} }}),\n", prop.Name, conds.Trim(',', ' '));
        }
    
        return validationModel + "};";
    }
    

    Usage:

    string validationModel = GenerateValidationModel<LoginModel>();
    

    Output:

    var loginViewModel = {
        UserName: ko.observable().extend({ minLength: 3, required: true}),
        Password: ko.observable().extend({ required: true}),
    };
    

    It's good idea to cache the output