【问题标题】:FluentValidation: Check if one of two fields are emptyFluentValidation:检查两个字段之一是否为空
【发布时间】:2014-02-02 14:37:01
【问题描述】:

我有这个模型

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }  
}

我想创建一个验证,其中 FirstName 或 LastName 必须由用户填写。 我安装了FluentValidation 并创建了一个customvalidator 类

public class PersonValidator:AbstractValidator<Person>
{
    public PersonValidator()
    {
        RuleFor((person=>person.FirstName)//don't know how to check if one is empty
    }
}

要检查一个字段,我可以这样做RuleFor(person =&gt; person.FirstName).NotNull();

但是我如何检查其中一个是否为空。

另外,是否可以通过fluentValidation 创建验证后,在客户端使用它来显示错误?

编辑1

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        FluentValidationModelValidatorProvider.Configure();
    }
//creating validation
namespace WebApplication1.Models.CustomValidator
{
    public class PersonValidator:AbstractValidator<Person>
    {
        public PersonValidator()
        {
            RuleFor(m => m.FirstName).NotEmpty().When(m => string.IsNullOrEmpty(m.LastName)).WithMessage("*Either First Name or Last Name is required");
            RuleFor(m => m.LastName).NotEmpty().When(m => string.IsNullOrEmpty(m.FirstName)).WithMessage("*Either First Name or Last Name is required");
        }
    }

}
//model class
[Validator(typeof(PersonValidator))]
public class Person
{
    public Person()
    {
        InterestList = new List<string>();
    }
    public int Id { get; set; }
    public int ContactId { get; set; }
    [RequiredIfEmpty("LastName")]
    public string FirstName { get; set; }
    [RequiredIfEmpty("FirstName")]
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
    public string Phone { get; set; }
    public string Country { get; set; }
    public List<string> InterestList { get; set; } 
}
//view
@model WebApplication1.Models.Person

<script src="@Url.Content("~/Scripts/jquery-1.8.2.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

@Html.ValidationSummary(true)
@using(Html.BeginForm("AddPerson","Person",FormMethod.Post))
{
    <div class="label">First Name</div>
    <div class="input-block-level">@Html.TextBoxFor(m=>m.FirstName)@Html.ValidationMessageFor(m=>m.FirstName)</div>
    <br/>
    <div class="label">Last Name</div>
    <div class="input-block-level">@Html.TextBoxFor(m=>m.LastName)@Html.ValidationMessageFor(m=>m.LastName)</div>
    <button type="submit" class="btn-primary">Submit</button>
}

【问题讨论】:

  • RequiredIfEmpty 属性是什么?

标签: c# .net asp.net-mvc validation fluentvalidation


【解决方案1】:

一个很好的规则集来检查两个字段之一是否为空,以及提出有意义的错误代码如下:

public CustomerSourceValidator()
    {
        CascadeMode = CascadeMode.StopOnFirstFailure;

        RuleFor(x => x)
            .NotNull().WithErrorCode("source_id_or_email_required")
            .When(source => source.Email == null && source.Id == null);

        RuleFor(x => x.Id)
            .NotNull().WithErrorCode("source_id_required")
            .Matches(CommonValidationRegex.CustomerIdRegexString).WithErrorCode("source_id_invalid")
            .When(source => source.Id != null);

        RuleFor(x => x.Email)
            .NotNull().WithErrorCode("source_email_required")
            .Matches(CommonValidationRegex.EmailRegexString).WithErrorCode("source_email_invalid")
            .When(source => source.Email != null);
    }

【讨论】:

    【解决方案2】:

    你可以使用When/Unless条件:

    RuleFor(m => m.FirstName).NotEmpty().When(m => string.IsNullOrEmpty(m.LastName));
    RuleFor(m => m.LastName).NotEmpty().When(m => string.IsNullOrEmpty(m.FirstName));
    

    RuleFor(m => m.FirstName).NotEmpty().Unless(m => !string.IsNullOrEmpty(m.LastName));
    RuleFor(m => m.LastName).NotEmpty().Unless(m => !string.IsNullOrEmpty(m.FirstName));
    

    至于您的第二个问题,FluentValidation 适用于客户端验证,但并非所有规则都受支持。 Here 你可以找到客户端支持的验证器:

    1. NotNull/NotEmpty
    2. 匹配(正则表达式)
    3. InclusiveBetween(范围)
    4. 信用卡
    5. 电子邮件
    6. EqualTo(跨属性相等比较)
    7. 长度

    对于不在列表中的规则,您必须编写自己的 FluentValidationPropertyValidator 并实施 GetClientValidationRules。您可以通过简单的搜索在StackOverflow 上找到一些这样的示例。

    【讨论】:

    • 我使用.NotEmpty.When 来显示客户端错误我应该怎么做?我将编辑我的问题,以便您查看我添加了哪些新内容。
    • 我刚刚意识到它不适用于何时和除非。但 fluentValidation 仍然无法正常工作
    • 有没有办法做到这一点,但不必用模型状态错误填充这两个属性?
    • 不适合我,它仍然抱怨一个字段丢失而另一个字段被填充
    【解决方案3】:

    最后,这对我有用。我想验证至少需要一个的三个属性。它只返回一次错误消息。

    RuleFor(p => p).Cascade(CascadeMode.StopOnFirstFailure)
                .Must(p => !string.IsNullOrWhiteSpace(p.FirstName))
                .When(p => p.Id == 0 && string.IsNullOrWhiteSpace(p.LastName)).WithMessage("At least one is required (Id, FirstName, LastName).")
                .Must(p => !string.IsNullOrWhiteSpace(p.LastName))
                .When(p => p.Id == 0 && string.IsNullOrWhiteSpace(p.FirstName)).WithMessage("At least one is required (Id, FirstName, LastName).")
                .Must(p => p.Id != 0)
                .When(p => string.IsNullOrWhiteSpace(p.FirstName) && string.IsNullOrWhiteSpace(p.LastName)).WithMessage("At least one is required (Id, FirstName, LastName).");
    

    【讨论】:

    • 你肯定只需要第一个 Must()/When()?
    • @sixeyes 你是在问还是说我可以改进?
    • 也许我遗漏了一些东西,但如果所有三个值都是 null / 0,第一个 Must() 将触发。为什么要打扰其他两个 Must()。如果您在@dummyDev 回答时收到不同的消息,那将是有道理的,但您的消息都是一样的。我复制了您的代码,因为它是我所追求的,但是一旦我编写了测试,我发现我不需要另一个 Must(),因此我的评论。
    【解决方案4】:

    我这样做是为了检查输入的费用是否与之前的费用相同。 如果费用与之前的费用相同,则会出错。这对我有用。

    public class CasualMealChargeValidator : AbstractValidator<CasualMealCharge>
    {
        public CasualMealChargeValidator(CasualMealCharge CMC)
        {
            //RuleFor(x => x.BankName).NotEmpty().When(pm => pm.PaymentMode == "Cheque").WithMessage("Enter Bank.");
            RuleFor(x => x).Must(x => x.DN != CMC.DN || x.BF != CMC.BF || x.LN != CMC.LN).WithMessage("Not Saved - Meal charges are same as current charges.").WithName("CMFor");
        }
    }
    

    【讨论】:

      【解决方案5】:

      试试这个

      RuleFor(person => person).Must(person => !string.IsNullOrEmpty(person.FirstName) || !string.IsNullOrEmpty(person.LastName))
      

      【讨论】:

      • 使用 ValidateAsync 时失败:(
      • 这对我不起作用。我收到以下错误:无法为表达式 item => item 自动确定属性名称。请通过调用“WithName”指定自定义属性名称。
      • @VladSchnakovszki 什么项目?
      • @FatShogun,在你的例子中相当于人。
      • @VladSchnakovszki afaik 尝试验证属性以外的内容时会产生错误。贴上你的相关代码,我看看能不能给你更好的答案。
      【解决方案6】:

      我不知道那个库,但如果你只是想检查这两个属性是否为空,那么你可以使用这个:

      <del>RuleFor(person =&gt; person.FirstName ?? person.LastName).NotNull();</del>

      EDIT 这不起作用,因为它会抛出一个InvalidOperationException。请改用 Zabavsky 的解决方案。

      【讨论】:

      • 这里 OP 真的想使用 NotEmpty() 来检查 null 或空字符串。
      • OP 明确表示他正在使用FluentValidation。我不知道我是否有过时的库,但是这个答案抛出了 System.InvalidOperationException 并带有错误消息:无法为表达式 person => (person.FirstName ?? person.LastName) 自动确定属性名称。请通过调用“WithName”指定自定义属性名称。
      • @IronGeek 你是对的。我编辑了答案。请改用 Zabavsky 的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-29
      • 2020-11-07
      • 2012-02-21
      • 2011-06-29
      • 1970-01-01
      相关资源
      最近更新 更多