Get annotation data attributes from a model

I want to create a custom validator on the client side, but I want to define validation rules using Data Annotations attributes at the business logic level. How can I access model validation attributes at runtime?

I want to write 'generator' which converts this code:

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

in that:

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

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

Could there be a reflection?

UPD

I found this method: MSDN . But I canโ€™t understand how to use it.

+8
c # asp.net-mvc data-annotations
source share
2 answers

This is a universal way 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 + "};"; } 

Using:

 string validationModel = GenerateValidationModel<LoginModel>(); 

Output:

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

Good idea to cache output

+13
source share

As mentioned above, I think the T4 can be worth it. The huge benefit is that it is not executed at runtime (although it can, if necessary), and you can avoid all possible problems with generating a runtime file. Hope enough starting point:

 <#@ template language="C#" debug="True" hostspecific="true" #> <#@ output extension="js" #> <#@ assembly name="System.Core" #> <#@ assembly name="EnvDTE" #> <#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.Linq" #> <#@ import namespace="EnvDTE" #> <# var serviceProvider = Host as IServiceProvider; if (serviceProvider == null) { throw new InvalidOperationException("Host is not IServiceProvider"); } var dte = serviceProvider.GetService(typeof(DTE)) as DTE; if (dte == null) { throw new InvalidOperationException("Unable to resolve DTE"); } var project = dte.Solution.Projects .OfType<Project>() .Single(p => p.Name == "ConsoleApplication2"); var model = project.CodeModel .CodeTypeFromFullName("MyApp.LoginModel") as CodeClass; //might want to have a list / find all items matching some rule #> var <#= Char.ToLowerInvariant(model.Name[0]) + model.Name.Remove(0, 1).Replace("Model", "ViewModel") #>= { <# foreach (var property in model.Members.OfType<CodeProperty>()) { var minLength = property.Attributes .OfType<CodeAttribute>() .FirstOrDefault(a => a.Name == "MinLength"); var required = property.Attributes .OfType<CodeAttribute>() .FirstOrDefault(a => a.Name == "Required"); var koAttributes = new List<String>(); if (minLength != null) koAttributes.Add("minLength: " + minLength.Value); if (required != null) koAttributes.Add("required: true"); #> <#= property.Name #>: ko.observable().extend({<#= String.Join(", ", koAttributes) #>}), <# } #> } 
+3
source share

All Articles