Get Data Annotations attributes from model

后端 未结 2 1222
被撕碎了的回忆
被撕碎了的回忆 2020-12-19 02:41

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

相关标签:
2条回答
  • 2020-12-19 03:11

    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

    0 讨论(0)
  • 2020-12-19 03:16

    As commented above - I believe T4 might be worth a shot here. A huge benefit is that it's not executed at runtime (though it can, if that's your requirement) and you can avoid all possible issues with runtime file generation. Hopefully a sufficient 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) #>}),
    <#
        }
    #>
    }
    
    0 讨论(0)
提交回复
热议问题