【问题标题】:Get Data Annotations attributes from model从模型中获取数据注释属性
【发布时间】:2013-11-07 10:05:43
【问题描述】:

我想创建自定义客户端验证器,但我想通过业务逻辑层的数据注释属性定义验证规则。如何在运行时访问模型验证属性?

我想写“生成器”,它将转换这段代码:

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

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

进入这个:

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

但当然不是来自 .cs 源。 =)

也许是反思?

UPD

我找到了这个方法:MSDN。但是不明白怎么用。

【问题讨论】:

  • 是的,反射。还有什么?
  • 反射始终是一种选择,但是您有什么特别的原因要避免从源头上这样做吗? T4 + EnvDTE 在这里似乎是一个不错的选择。
  • @HenkHolterman 我已经阅读了 mvc 源码,发现了这个方法:msdn.microsoft.com/en-us/library/… 但不明白如何使用它。也许有人有比反思更好的主意? =)

标签: c# asp.net asp.net-mvc data-annotations validationattribute


【解决方案1】:

这是通用的方法:

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

用法:

string validationModel = GenerateValidationModel<LoginModel>();

输出:

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

缓存输出是个好主意

【讨论】:

    【解决方案2】:

    如上所述 - 我相信 T4 可能值得一试。一个巨大的好处是它不会在运行时执行(尽管它可以,如果这是您的要求)并且您可以避免运行时文件生成的所有可能问题。希望是一个足够的起点:

    <#@ 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) #>}),
    <#
        }
    #>
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-16
      • 2015-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-10
      相关资源
      最近更新 更多