【问题标题】:Get object from client validation attribute从客户端验证属性获取对象
【发布时间】:2020-09-24 11:48:59
【问题描述】:

我在客户端验证属性中有下一个“AddValidation”方法(继承自ValidationAttribute,IClientModelValidator)

public void AddValidation(ClientModelValidationContext context)
    {
        var viewContext = context.ActionContext as ViewContext;
        var modelType = context.ModelMetadata.ContainerType;
        var model = viewContext?.ViewData.Model;
        var maxDate = (DateTime?)modelType.GetProperty(_maxDateName)?.GetValue(model, null);
        var minDate = (DateTime?)modelType.GetProperty(_minDateName)?.GetValue(model, null);
         var errorMessage = string.Format(ErrorMessageString, minDate?.ToString("MM/dd/yyyy"), maxDate?.ToString("MM/dd/yyyy"));
        
        context.Attributes.Add("data-val-preliminaryraterangedate", errorMessage);
        context.Attributes.Add("data-val-preliminaryraterangedate-rangedates",
            JsonConvert.SerializeObject(new {MaxDateName = $"#{_maxDateName}", MinDateName = $"#{_minDateName}"}));
    }

如何获取模型对象以获取属性值?仅当模型对象包含原始类型时,此示例才适用。并且不能使用包含复杂类型的模型对象

【问题讨论】:

    标签: asp.net asp.net-core


    【解决方案1】:

    您可以通过model直接获取该属性,但需要指定其类型。

    下面是一个演示:

    型号:

    public class TimeModel
    {
        public string Name { get; set; }
        public MyTime MyTime { get; set; }
    }
    public class MyTime
    {
        [Ranges]
        public DateTime RangeDatetime { get; set; }
    }
    

    范围属性:

    public class RangesAttribute : ValidationAttribute, IClientModelValidator
    {
        public void AddValidation(ClientModelValidationContext context)
        {
            var viewContext = context.ActionContext as ViewContext;
            var modelType = context.ModelMetadata.ContainerType;
            var model = (TimeModel)viewContext?.ViewData.Model;
            var name = model.Name;
            var rangeDatetime = model.MyTime.RangeDatetime
            //...
        }
    }
    

    控制器:

    public IActionResult Index()
    {
        TimeModel model = new TimeModel
        {
            Name = "AAAAA",
            MyTime = new MyTime {  RangeDatetime = DateTime.Now}
        };
    
        return View(model);
    }
    

    结果:

    更新:

    public void AddValidation(ClientModelValidationContext context)
    {
        var viewContext = context.ActionContext as ViewContext;
        var model = viewContext.ViewData.Model;
        Dictionary<string, string> myDict = new Dictionary<string, string>();
        Type type = model.GetType();
        foreach (PropertyInfo pi in type.GetProperties())
        {
            var subModel = pi.GetValue(model, null);
            Type subtype = pi.GetValue(model, null).GetType();
            if (!subtype.IsPrimitive && !subtype.Equals(typeof(string)))
            {
                var pii = subtype.GetProperties();
                foreach (PropertyInfo item in pii)
                {
                    myDict[item.Name] = item.GetValue(subModel, null)?.ToString();
                }
            }
            else
            {
                myDict[pi.Name] = pi.GetValue(model, null)?.ToString();
            }
        }
    }
    

    【讨论】:

    • 好点,但如果我有不同的模型var model = (TimeModel)viewContext?.ViewData.Model; 不仅是 TimeModel
    • 当模型对象只包含原始类型时它也会打破大小写
    • 如果模型是动态的,你可能需要使用反射,看我的更新。
    • 很好的解决方案,但只有在模型中只有一个复杂模型时才有效,请参阅下面我如何解决此案例的解决方案。
    【解决方案2】:
    var viewContext = context.ActionContext as ViewContext;
            var modelType = context.ModelMetadata.ContainerType;
            var instance = viewContext?.ViewData.Model;
            var model = instance?.GetType().Name == modelType.Name
                ? instance
                : instance?.GetType()?.GetProperties().First(x => x.PropertyType.Name == modelType.Name)
                    .GetValue(instance, null);
            var maxDate = (DateTime?)modelType.GetProperty(_maxDateName)?.GetValue(model, null);
            var minDate = (DateTime?)modelType.GetProperty(_minDateName)?.GetValue(model, null);
             var errorMessage = string.Format(ErrorMessageString, minDate?.ToString("MM/dd/yyyy"), maxDate?.ToString("MM/dd/yyyy"));
            
            context.Attributes.Add("data-val-preliminaryraterangedate", errorMessage);
            context.Attributes.Add("data-val-preliminaryraterangedate-rangedates",
                JsonConvert.SerializeObject(new {MaxDateName = $"#{_maxDateName}", MinDateName = $"#{_minDateName}"}));
    

    您可以从context.ModelMetadata.ContainerType; 获取您需要的类型并将其与父模型属性类型进行比较

    【讨论】:

    • 你是救生员!这是超级有用的。一个小问题,它可能应该是 var model = instance?.GetType().FullName == modelType.FullName (我有一个视图模型,其类型名称与其属性之一相同,但名称空间不同......我发誓我会的清理我的烂摊子)。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 2014-06-15
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 2015-03-26
    • 1970-01-01
    相关资源
    最近更新 更多