C# 针对包含逗号分隔电子邮件的字符串进行验证

C# 针对包含逗号分隔电子邮件的字符串进行验证,c#,asp.net-mvc-3,validation,fluentvalidation,C#,Asp.net Mvc 3,Validation,Fluentvalidation,我试图在MVC模型中验证此属性,该模型可以包含零个或多个以逗号分隔的电子邮件地址: public class DashboardVM { public string CurrentAbuseEmails { get; set; } ... } 问题是如何使用电子邮件地址的内置fluent验证规则来实现这一点? 现在我有了一个使用Must和正则表达式的解决方案,但我没有找到它。。足够优雅 public DashboardVMValidator() {

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

public class DashboardVM
{
    public string CurrentAbuseEmails { get; set; }
    ...
}
问题是如何使用电子邮件地址的内置fluent验证规则来实现这一点? 现在我有了一个使用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()在内的最接近的解决方案是在下面创建一个自定义验证器,并从字符串中对每封电子邮件调用Validate,但由于某种原因,这没有起作用(AbuseEmailValidator在对每封电子邮件调用Validator.Validate时无法获取谓词x=>x)

public类:seemailvalidator:AbstractValidator
{
公共邮件验证程序()
{
RuleFor(x=>x).EmailAddress().WithMessage(“电子邮件地址无效”);
}
}

有没有简单的方法可以做到这一点?与此解决方案类似,但使用一个字符串而不是字符串列表,因为我无法使用SetCollectionValidator(或者我可以吗?):

您可以尝试以下方法:

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; }
}
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 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");
        }
    }
公共类InvoiceValidator:AbstractValidator
{
公共发票验证器()
{
规则(m=>m.EmailAddressTo)
.Must(CommonValidators.CheckValidEmails).WithMessage(“提供的某些电子邮件无效”);
}
}
公共静态类CommonValidator
{
公共静态bool CheckValidEmails(字符串arg)
{
var list=arg.Split(“;”);
var isValid=true;
var emailValidator=新的emailValidator();
foreach(列表中的变量t)
{
isValid=emailValidator.Validate(新的EmailModel{Email=t.Trim()});
如果(!isValid)
打破
}
返回有效;
}
}
公共类EmailValidator:AbstractValidator
{
公共电子邮件验证程序()
{
RuleFor(x=>x.Email).EmailAddress();
}
}
公共类电子邮件模型
{
公共字符串电子邮件{get;set;}
}

如果您使用中间poco,它似乎可以正常工作。在这种情况下,我的电子邮件以“;”分隔。希望有帮助。

上面提供的答案很好,但很旧。因此,一些代码无法与FluentValidation Nuget包的never版本一起使用。至少我有构建错误。此外,解决方案可能更复杂。 建议使用以下方法:

型号:

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 = ';';
    }
}
公共密封类电子邮件
{
来自{get;set;}的公共字符串
/// 
///电子邮件地址至(可设置为分隔列表,默认值:;)
/// 
{get;set;}的公共字符串
//.....
/// 
///多个电子邮件地址的分隔字符
/// 
公共字符EmailAddressSeparator{get;set;}
公共电子邮件()
{
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));
        }
    }
}
公共静态类CommonValidator
{
公共静态bool CheckValidEmails(电子邮件、字符串电子邮件)
{
if(string.IsNullOrWhiteSpace(电子邮件))
{
返回true;
}
var list=emails.Split(email.EmailAddressSeparator);
var isValid=true;
foreach(列表中的变量t)
{
var email=newemailmodel{email=t.Trim()};
var validator=新的EmailModelValidator();
isValid=validator.Validate(电子邮件).isValid;
如果(!isValid)
{
打破
}
}
返回有效;
}
私有类模型
{
公共字符串电子邮件{get;set;}
}
私有类EmailModelValidator:AbstractValidator
{
公共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.");
        }
    }
public class EmailsModelValidator : AbstractValidator<EmailsModel>
{
    public EmailsModelValidator()
    {
        RuleFor(x => x.Emails).CheckValidEmails(";");
        RuleFor(x => x.Emails).CheckValidEmails(x => x.EmailsSeparator);
    }
}
公共类EmailValidator:AbstractValidator
{
公共电子邮件验证程序()
{
(x=>x.To).NotEmpty()的规则
.Must(CommonValidators.CheckValidEmails)
.WithMessage($“{nameof(To)}”提供的某些电子邮件不是有效的电子邮件地址。”);
}
}

您可以编写自定义验证程序扩展。 通过这种方式,您可以定义所需的任何分隔符,将其用于每个字符串属性而不仅仅是特定属性,并根据条件添加不同的消息

您可以从文档中了解有关自定义验证器的更多信息:

自定义验证程序扩展:

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();
        }
    }
}
       
公共静态类验证扩展
{
公共静态IRuleBuilderInitial CheckValidEmails(此IRuleBuilder规则生成器,字符串分隔符)
{
bool是有效的;
var emailValidator=新的emailValidator();
返回ruleBuilder.Custom((emailsStr,context)=>
{
if(string.IsNullOrWhiteSpace(emailsStr))
{
context.AddFailure($“{context.DisplayName}”不能为空);
返回;
}
var emails=emailsStr.Split(分隔符);
foreach(电子邮件中的var电子邮件)
{
isValid=emailValidator.Validate(email.Trim()).isValid;
如果(!isValid)
{
context.AddFailure($“{email}”不是有效的电子邮件地址”);
打破
}
}
});
}
私有类EmailValidator:AbstractValidator
{
公共电子邮件验证程序()
{
RuleFor(x=>x).EmailAddress();
}
}
}
如果希望将分隔符作为模型属性,则可以编写如下扩展:

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; }
}
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 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");
        }
    }
公共静态IRuleBuilder初始检查有效性文件(此IRuleBuilder规则生成器,函数分隔符选择器)
{
if(separatorSelector==null)
抛出新ArgumentNullException(nameof(separatorSelector),$“{nameof(separatorSelector)}不能为null”);
bool是有效的;
var电子邮件验证程序=
    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");
        }
    }