如何通过属性强制字符串的格式?
How to enforce the format of a string via attribute?
我有一个数据模型,它是一个字符串列表。这将由用户输入填充,但我需要确保他们提供的字符串的格式仅为“something:something”。
即它必须包含一个 冒号 后跟另一组字符(最小长度为 4)。当前的模型(在需要结肠附件之前)是沿着:
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
public List<string> ListOfStrings { get; set; }
我的旧实现的唯一要求只是长度要求。我想知道实施这种新格式“string:string”的最佳方式是什么?我想拒绝不包含后跟 4 个或更多字符的冒号的字符串。
提前感谢您的任何建议。
由于您现在要验证数组的内容而不仅仅是数组本身,因此您最简单的解决方案是自定义属性:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class MyCustomValidatorAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
List<string> list = value as List<string>;
if (list == null)
{
// not a string list, might want to handle this directly or just let it fall back to the other validators
return base.IsValid(value, validationContext);
}
foreach (var item in array)
{
var hasError = // your string validation here
if (hasError) {
return new ValidationResult("Your validation error description here");
}
}
return ValidationResult.Success;
}
}
一旦您确定了该验证器的详细信息,用法将是:
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
[MyCustomValidator]
public List<string> ListOfStrings { get; set; }
虽然不知道您的期望是什么,但我能猜到的最适合您的实际字符串验证的可能是这样的:
// declare this only once before the loop
var isValidStringRegex = new Regex("^\w+:\w{4,}$");
var hasError = !isValidStringRegex.IsMatch(item);
此外,这并不是您问题的真正答案,但请查看 FluentValidation 是否适合您的项目。一旦你习惯了,编写测试就容易得多,也更容易思考。
你可以使用正则表达式,this is information about regex in msnd
在你的例子中,字符串 pattam 是 "\w+:(\w{4,})"
在 the regex online tool 或控制台中尝试
public static void Main(string[] args)
{
System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"\w+:(\w{4,})");
//Your code goes here
Console.WriteLine(r.IsMatch("string:string").ToString());
}
提出几个备选方案。您可以根据自己的需要和适用性参考和应用它。
解决方案 1:
应用IValidatableObject.Validate(ValidationContext)
您可以在 IValidatableObject.Validate(ValidationContext) Method 中编写您的验证逻辑。
先决条件:
- class 必须使用
IValidatableObject
接口实现。
public class Input : IValidatableObject
{
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
public List<string> ListOfStrings { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (this.ListOfStrings == null || !this.ListOfStrings.Any())
{
results.Add(new ValidationResult("ListOfStrings is required"));
return results;
}
var regex = new Regex(@"^\w+:\w{4,}$");
var hasUnmatched = this.ListOfStrings.Any(x => !regex.IsMatch(x));
if (hasUnmatched)
{
results.Add(new ValidationResult("ListOfStrings contains invalid format string"));
return results;
}
return results;
}
}
注:
感谢@Callum Morrisson 的回答,解决方案 1 仅在不需要在不同 class.
中应用验证逻辑时才是首选
解决方案 2:
CustomValidation
属性与辅助方法
感谢@JohnWu 的建议,CustomValidationAttribute 使用 Helper 方法也是另一种选择。
public class Input
{
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
[CustomValidation(
typeof(InputValidationHelper),
"ValidateListOfStringsRegex",
ErrorMessage = "ListOfStrings contains invalid format string")]
public List<string> ListOfStrings { get; set; }
}
public class InputValidationHelper
{
public static ValidationResult ValidateListOfStringsRegex(List<string> listOfStrings)
{
if (listOfStrings == null || !listOfStrings.Any())
{
return new ValidationResult("ListOfStrings is required");
}
var regex = new Regex(@"^\w+:\w{4,}$");
var hasUnmatched = listOfStrings.Any(x => !regex.IsMatch(x));
if (hasUnmatched)
{
return new ValidationResult(null);
}
return ValidationResult.Success;
}
}
注:
将推荐解决方案 2,因为验证逻辑可以在不同的 classes 属性中重复使用 [不要重复自己 (D.R.Y)]。
看来 RegularExpressionAttribute 可以胜任:
public class CustomerMetaData
{
// Allow up to 40 uppercase and lowercase
// characters. Use custom error.
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$",
ErrorMessage = "Characters are not allowed.")]
public object FirstName;
// Allow up to 40 uppercase and lowercase
// characters. Use standard error.
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public object LastName;
}
另请注意,您也可以随时进行验证,例如作为控制器代码的一部分,没有任何属性。
我有一个数据模型,它是一个字符串列表。这将由用户输入填充,但我需要确保他们提供的字符串的格式仅为“something:something”。
即它必须包含一个 冒号 后跟另一组字符(最小长度为 4)。当前的模型(在需要结肠附件之前)是沿着:
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
public List<string> ListOfStrings { get; set; }
我的旧实现的唯一要求只是长度要求。我想知道实施这种新格式“string:string”的最佳方式是什么?我想拒绝不包含后跟 4 个或更多字符的冒号的字符串。
提前感谢您的任何建议。
由于您现在要验证数组的内容而不仅仅是数组本身,因此您最简单的解决方案是自定义属性:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class MyCustomValidatorAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
List<string> list = value as List<string>;
if (list == null)
{
// not a string list, might want to handle this directly or just let it fall back to the other validators
return base.IsValid(value, validationContext);
}
foreach (var item in array)
{
var hasError = // your string validation here
if (hasError) {
return new ValidationResult("Your validation error description here");
}
}
return ValidationResult.Success;
}
}
一旦您确定了该验证器的详细信息,用法将是:
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
[MyCustomValidator]
public List<string> ListOfStrings { get; set; }
虽然不知道您的期望是什么,但我能猜到的最适合您的实际字符串验证的可能是这样的:
// declare this only once before the loop
var isValidStringRegex = new Regex("^\w+:\w{4,}$");
var hasError = !isValidStringRegex.IsMatch(item);
此外,这并不是您问题的真正答案,但请查看 FluentValidation 是否适合您的项目。一旦你习惯了,编写测试就容易得多,也更容易思考。
你可以使用正则表达式,this is information about regex in msnd
在你的例子中,字符串 pattam 是 "\w+:(\w{4,})"
在 the regex online tool 或控制台中尝试
public static void Main(string[] args)
{
System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"\w+:(\w{4,})");
//Your code goes here
Console.WriteLine(r.IsMatch("string:string").ToString());
}
提出几个备选方案。您可以根据自己的需要和适用性参考和应用它。
解决方案 1:
应用IValidatableObject.Validate(ValidationContext)
您可以在 IValidatableObject.Validate(ValidationContext) Method 中编写您的验证逻辑。
先决条件:
- class 必须使用
IValidatableObject
接口实现。
public class Input : IValidatableObject
{
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
public List<string> ListOfStrings { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (this.ListOfStrings == null || !this.ListOfStrings.Any())
{
results.Add(new ValidationResult("ListOfStrings is required"));
return results;
}
var regex = new Regex(@"^\w+:\w{4,}$");
var hasUnmatched = this.ListOfStrings.Any(x => !regex.IsMatch(x));
if (hasUnmatched)
{
results.Add(new ValidationResult("ListOfStrings contains invalid format string"));
return results;
}
return results;
}
}
注: 感谢@Callum Morrisson 的回答,解决方案 1 仅在不需要在不同 class.
中应用验证逻辑时才是首选解决方案 2:
CustomValidation
属性与辅助方法
感谢@JohnWu 的建议,CustomValidationAttribute 使用 Helper 方法也是另一种选择。
public class Input
{
[Required(ErrorMessage = "some error msg")]
[MinLength(10)]
[CustomValidation(
typeof(InputValidationHelper),
"ValidateListOfStringsRegex",
ErrorMessage = "ListOfStrings contains invalid format string")]
public List<string> ListOfStrings { get; set; }
}
public class InputValidationHelper
{
public static ValidationResult ValidateListOfStringsRegex(List<string> listOfStrings)
{
if (listOfStrings == null || !listOfStrings.Any())
{
return new ValidationResult("ListOfStrings is required");
}
var regex = new Regex(@"^\w+:\w{4,}$");
var hasUnmatched = listOfStrings.Any(x => !regex.IsMatch(x));
if (hasUnmatched)
{
return new ValidationResult(null);
}
return ValidationResult.Success;
}
}
注: 将推荐解决方案 2,因为验证逻辑可以在不同的 classes 属性中重复使用 [不要重复自己 (D.R.Y)]。
看来 RegularExpressionAttribute 可以胜任:
public class CustomerMetaData { // Allow up to 40 uppercase and lowercase // characters. Use custom error. [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$", ErrorMessage = "Characters are not allowed.")] public object FirstName; // Allow up to 40 uppercase and lowercase // characters. Use standard error. [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")] public object LastName; }
另请注意,您也可以随时进行验证,例如作为控制器代码的一部分,没有任何属性。