验证包含逗号分隔电子邮件的字符串

Mat*_*tej 4 c# validation fluentvalidation asp.net-mvc-3

我正在尝试在MVC模型中验证此属性,该模型可以包含由逗号分隔的零个或多个电子邮件地址:

public class DashboardVM
{
    public string CurrentAbuseEmails { get; set; }
    ...
}
Run Code Online (Sandbox Code Playgroud)

问题是我如何使用电子邮件地址的内置流畅验证规则?现在我有一个使用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
    }
Run Code Online (Sandbox Code Playgroud)

到目前为止,最接近的解决方案包括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");
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法以一些简单的方式做到这一点?类似于这个解决方案的东西,但有一个字符串而不是字符串列表,因为我不能使用SetCollectionValidator(或者我可以吗?):如何使用Fluent验证对列表中的每个字符串进行验证?

小智 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; }
}
Run Code Online (Sandbox Code Playgroud)

如果你使用中间poco似乎工作正常.我的电子邮件以";"分隔 在这种情况下.希望能帮助到你.


Jac*_* A. 6

从版本 9 开始,FluentValidation 支持此功能,不需要使用TransformForEach方法的自定义验证器。

在9.0-9.4版本中,你可以这样写:

RuleFor(x => x.List)
    .Transform(list => list.Split(','))
    .ForEach(itemRule => itemRule.EmailAddress());
Run Code Online (Sandbox Code Playgroud)

在 9.5 及更高版本中,RuleFor不与 一起使用Transform,因此您可以这样编写:

Transform(x => x.List, list => list.Split(','))
    .ForEach(itemRule => itemRule.EmailAddress());
Run Code Online (Sandbox Code Playgroud)

要处理空值,请在委托中使用空合并运算符Transform

list => (list ?? "").Split(',')
Run Code Online (Sandbox Code Playgroud)

要处理空白,您可能需要修剪列表中的每个项目。您可以添加一个Select子句:

list => (list ?? "").Split(',')
    .Select(item => item.Trim())
Run Code Online (Sandbox Code Playgroud)

如果要忽略空项,请添加一个Where子句:

list => (list ?? "").Split(',')
    .Select(item => item.Trim())
    .Where(item => !string.IsNullOrEmpty(item))
Run Code Online (Sandbox Code Playgroud)

要要求列表中至少有一项,请添加规则NotEmpty。所以最终版本 9.5+ 代码将如下所示:

Transform(x => x.List, 
    list => (list ?? "").Split(',')
        .Select(item => item.Trim())
        .Where(item => !string.IsNullOrEmpty(item)))
    .NotEmpty()
    .ForEach(itemRule => itemRule.EmailAddress());
Run Code Online (Sandbox Code Playgroud)

对于 FluentValidation 11+,Transform样式方法已被弃用。他们推荐的做法是将解析逻辑移至正在验证的模型中。基于 OP 的示例如下所示:

// Model Class
public class DashboardVM
{
    public string CurrentAbuseEmails { get; set; }
    public List<string> CurrentAbuseEmailsParsed {
        get {
            return (CurrentAbuseEmails ?? "").Split(',')
                .Select(item => item.Trim())
                .Where(item => !string.IsNullOrEmpty(item))
                .ToList();
        }
    }
    ...
}

// Validator (note that the Parsed property is validated)
RuleFor(x => x.CurrentAbuseEmailsParsed)
    .NotEmpty()
    .ForEach(itemRule => itemRule.EmailAddress());
Run Code Online (Sandbox Code Playgroud)

或者,可以使用自定义验证器,如其他答案中所述。