我正在尝试在MVC模型中验证此属性,该模型可以包含由逗号分隔的零个或多个电子邮件地址:
public class DashboardVM
{
public string CurrentAbuseEmails { get; set; }
...
}
问题是我如何使用电子邮件地址的内置流畅验证规则? 现在我有一个使用Must和正则表达式的解决方案,但是我找不到它......优雅。
public DashboardVMValidator()
{
RuleFor(x => x.CurrentAbuseEmails).Must(BeValidDelimitedEmailList).WithMessage("One or more email addresses are not valid.");
}
private bool BeValidDelimitedEmailList(string delimitedEmails)
{
//... match very very long reg. expression
}
到目前为止,最接近的解决方案包括RuleFor(...)。EmailAddress()在下面创建了一个自定义Validator,并在字符串中的每封电子邮件上调用Validate,但由于某种原因这不起作用(AbuseEmailValidator无法使用)得到我的谓词x => x - 在每封电子邮件上调用validator.Validate时。)
public class AbuseEmailValidator : AbstractValidator<string>
{
public AbuseEmailValidator()
{
RuleFor(x => x).EmailAddress().WithMessage("Email address is not valid");
}
}
有没有办法以一种简单的方式做到这一点?类似于这个解决方案的东西,但是有一个字符串而不是字符串列表,因为我不能使用SetCollectionValidator(或者我可以吗?):How do you validate against each string in a list using Fluent Validation?
答案 0 :(得分:6)
您可以尝试这样的事情:
public class InvoiceValidator : AbstractValidator<ContractInvoicingEditModel>
{
public InvoiceValidator()
{
RuleFor(m => m.EmailAddressTo)
.Must(CommonValidators.CheckValidEmails).WithMessage("Some of the emails provided are not valid");
}
}
public static class CommonValidators
{
public static bool CheckValidEmails(string arg)
{
var list = arg.Split(';');
var isValid = true;
var emailValidator = new EmailValidator();
foreach (var t in list)
{
isValid = emailValidator.Validate(new EmailModel { Email = t.Trim() }).IsValid;
if (!isValid)
break;
}
return isValid;
}
}
public class EmailValidator : AbstractValidator<EmailModel>
{
public EmailValidator()
{
RuleFor(x => x.Email).EmailAddress();
}
}
public class EmailModel
{
public string Email { get; set; }
}
如果你使用中间poco似乎工作正常。我的电子邮件由&#34;;&#34;在这种情况下。希望它有所帮助。
答案 1 :(得分:1)
上面提供的答案很好,但是很旧了。因此,某些代码永远无法使用FluentValidation Nuget软件包的版本。至少我遇到了构建错误。同样,解决方案可以更复杂。 推荐使用此:
型号:
public sealed class Email
{
public string From { get; set; }
/// <summary>
/// Email address(es) to (can be settable separated list, default: ;)
/// </summary>
public string To { get; set; }
//.....
/// <summary>
/// Separator char for multiple email addresses
/// </summary>
public char EmailAddressSeparator { get; set; }
public Email()
{
EmailAddressSeparator = ';';
}
}
自定义验证器:
public static class CommonValidators
{
public static bool CheckValidEmails(Email email, string emails)
{
if(string.IsNullOrWhiteSpace(emails))
{
return true;
}
var list = emails.Split(email.EmailAddressSeparator);
var isValid = true;
foreach (var t in list)
{
var email = new EmailModel { Email = t.Trim() };
var validator = new EmailModelValidator();
isValid = validator.Validate(email).IsValid;
if (!isValid)
{
break;
}
}
return isValid;
}
private class EmailModel
{
public string Email { get; set; }
}
private class EmailModelValidator : AbstractValidator<EmailModel>
{
public EmailModelValidator()
{
RuleFor(x => x.Email).EmailAddress(EmailValidationMode.AspNetCoreCompatible).When(x => !string.IsNullOrWhiteSpace(x.Email));
}
}
}
用法:
public class EmailValidator : AbstractValidator<Email>
{
public EmailValidator()
{
RuleFor(x => x.To).NotEmpty()
.Must(CommonValidators.CheckValidEmails)
.WithMessage($"'{nameof(To)}' some of the emails provided are not a valid email address.");
}
}
答案 2 :(得分:0)
您可以编写自定义验证器扩展。 通过这种方式,您可以定义任何您想要的分隔符,将其用于每个字符串属性而不仅仅是特定属性,并根据条件添加不同的消息。
您可以从文档中了解有关自定义验证器的更多信息:https://docs.fluentvalidation.net/en/latest/custom-validators.html
自定义验证器扩展:
public static class ValidatorExtensions
{
public static IRuleBuilderInitial<T, string> CheckValidEmails<T>(this IRuleBuilder<T, string> ruleBuilder, string separator)
{
bool isValid;
var emailValidator = new EmailValidator();
return ruleBuilder.Custom((emailsStr, context) =>
{
if (string.IsNullOrWhiteSpace(emailsStr))
{
context.AddFailure($"'{context.DisplayName}' must not be empty");
return;
}
var emails = emailsStr.Split(separator);
foreach (var email in emails)
{
isValid = emailValidator.Validate(email.Trim()).IsValid;
if (!isValid)
{
context.AddFailure($"'{email}' is not a valid email address");
break;
}
}
});
}
private class EmailValidator : AbstractValidator<string>
{
public EmailValidator()
{
RuleFor(x => x).EmailAddress();
}
}
}
如果您希望将分隔符作为模型属性,那么您可以像这样编写扩展:
public static IRuleBuilderInitial<T, string> CheckValidEmails<T>(this IRuleBuilder<T, string> ruleBuilder, Func<T, string> separatorSelector)
{
if (separatorSelector == null)
throw new ArgumentNullException(nameof(separatorSelector), $"{nameof(separatorSelector)} cannot be null");
bool isValid;
var emailValidator = new EmailValidator();
return ruleBuilder.Custom((emailsStr, context) =>
{
if (string.IsNullOrWhiteSpace(emailsStr))
{
context.AddFailure($"'{context.DisplayName}' must not be empty");
return;
}
var separator = separatorSelector.Invoke((T) context.InstanceToValidate);
var emails = emailsStr.Split(separator);
foreach (var email in emails)
{
isValid = emailValidator.Validate(email.Trim()).IsValid;
if (!isValid)
{
context.AddFailure($"'{email}' is not a valid email address");
break;
}
}
});
}
示例模型:
public class EmailsModel
{
/// <summary>
/// emails separated by ;
/// </summary>
public string Emails { get; set; }
public string EmailsSeparator { get; set; } = ";";
}
用法:
public class EmailsModelValidator : AbstractValidator<EmailsModel>
{
public EmailsModelValidator()
{
RuleFor(x => x.Emails).CheckValidEmails(";");
RuleFor(x => x.Emails).CheckValidEmails(x => x.EmailsSeparator);
}
}
答案 3 :(得分:0)
我想要一些更简单的东西,并且能够将 .When(), .Unless()
和 .WithMessage()
等条件链接起来。因此,我使用扩展方法构建了 Burhan Savci 的解决方案:
public static class ValidatorExtensions
{
public static IRuleBuilderOptions<T, string> CheckValidEmails<T>(this IRuleBuilder<T, string> ruleBuilder, string separator)
{
var emailValidator = new EmailValidator();
return ruleBuilder.Must(emails => emails.Split(separator).All(email => emailValidator.Validate(email.Trim()).IsValid));
}
private class EmailValidator : AbstractValidator<string>
{
public EmailValidator()
{
RuleFor(x => x).EmailAddress();
}
}
}
就我而言,我有一个 CRQS 命令,用于导出带有更多输入选项的数据,包括选择导出类型(文件/电子邮件/其他选项)的下拉菜单。
public class Command : IRequest<Result>
{
public string EmailAddress{ get; set; }
public ExportType ExportType{ get; set; }
}
然后像这样使用它:
public class Validator : AbstractValidator<Command>
{
public Validator()
{
RuleFor(c => c.ExportOptions.EmailAddress).CheckValidEmails(",").When(c => c.ExportType == ExportType.Email).WithMessage("One or more email addresses are not valid");
}
}