I have a model which looks like this:
public class ChartModel
{
public List<int> GoalList { get; set; } = new List<int>();
public List<string?> LabelList { get; set; } = new List<string?>();
[Required]
[StringLength(maximumLength: 75)]
public string? LabelValidation { get; set; }
[DefaultSettingValue("0")]
[Range(1, 100)]
public int GoalValidation { get; set; }
}
I want the attributes above each List to apply to the int
and string
types, respectively, inside them. Seeing that just doing something like:
[Required]
[StringLength(maximumLength: 75)]
public List<string?> LabelList { get; set; } = new List<string?>();
doesn't work, I made the LabelValidation
and GoalValidation
variables with the intention of using them in an HTML form where the user inputs values for labels and goals into the list like so:
<input asp-for="LabelList[ind]" placeholder="@ViewBag.Chart.LabelList[ind]" value="@ViewBag.Chart.LabelList[ind]" />
<span asp-validation-for="LabelValidation" ></span>
<input asp-for="GoalList[ind]" placeholder="@ViewBag.Chart.GoalList[ind]" value="@ViewBag.Chart.GoalList[ind]" />
<span asp-validation-for="GoalValidation" ></span>
but that does not seem to work either. How can I apply these attributes to the elements within the lists?
CodePudding user response:
Consider to use custom attributes for this purpose:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IntListValidationAttribute : ValidationAttribute
{
public int Minimum { get; private set; }
public int Maximum { get; private set; }
public IntListValidationAttribute(string errorMessage, int minimum, int maximum)
: base(errorMessage)
{
Minimum = minimum;
Maximum = maximum;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var obj = validationContext.ObjectInstance;
if (value is List<int> list)
{
PropertyInfo[] myPropertyInfo = obj.GetType().GetProperties();
for (int i = 0; i < myPropertyInfo.Length; i )
{
if (myPropertyInfo[i].PropertyType.Equals(typeof(List<int>)))
{
foreach (var item in list)
{
if (item < Minimum || item > Maximum)
{
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
}
}
return new ValidationResult(ErrorMessage);
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class StringListValidationAttribute : ValidationAttribute
{
public int MaximumLength { get; private set; }
public StringListValidationAttribute(string errorMessage, int maximumLength)
: base(errorMessage)
{
this.MaximumLength = maximumLength;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var obj = validationContext.ObjectInstance;
if (value is List<string> list)
{
PropertyInfo[] myPropertyInfo = obj.GetType().GetProperties();
for (int i = 0; i < myPropertyInfo.Length; i )
{
if (myPropertyInfo[i].PropertyType.Equals(typeof(List<string>)))
{
foreach (var item in list)
{
if (item.Length > MaximumLength)
{
return new ValidationResult(ErrorMessage);
}
}
return ValidationResult.Success;
}
}
}
return new ValidationResult(ErrorMessage);
}
}
And then apply the attributes to properties:
public class ChartModel
{
[IntListValidation("Validation error", minimum: 2, maximum: 99)]
public List<int> GoalList { get; set; } = new List<int>();
[StringListValidation("Validation error", maximumLength: 15)]
public List<string> LabelList { get; set; } = new List<string>();
}