使用流畅验证比较两个可空日期时间的可重用方法

时间:2015-12-30 22:30:27

标签: c# asp.net-mvc fluentvalidation

我正在开发一个包含许多复杂验证规则的项目。我们正在使用Fluent验证来帮助解决这个问题,这是一个很棒的工具。但是,我们的模型通常有一对Nullable Datetimes,表示某事物的开始和结束。我正在处理的当前模型有三个不同的对,我注意到验证是不一致的,因为我们每次都在为这种情况写出验证规则。至少不干。我正在寻找一种通过Fluent验证来验证一对日期时间的方法。

到目前为止,我找到了两种方法,但两种方法都不合适。第一种是使用如下所述的自定义PropertyValidator,但使用此属性只能访问一个属性。我无法找到传递两个日期时间的方法,并且无法在父模型中传递,因为这将在许多模型上使用(可以使用接口执行某些操作,但需要更改许多模型。 )。 Fluent validation with dynamic message

第二种方法是使用Must和谓词重载,这样我就可以传递两个日期时间。这有效,但我无法弄清楚如何传回任何有关发生错误的消息,它是真还是假。这是我目前的测试代码:

RuleFor(i => i.Start)
            .Must((model,start) => BeValidDatePair(start, model.End));

public bool BeValidDatePair(DateTime? start, DateTime? end)
    {
        // Both values must be set or none
        if (start.HasValue && !end.HasValue)
        {
            return false;
        }
        if (end.HasValue && !start.HasValue)
        {
            return false;
        }

        // End cannot exceed start by two years
        if (end.Value > start.Value.AddYears(2))
        {
            return false;
        }

        return true;
    }

理想情况下,我会有两个功能,一个用于开始日期,一个用于结束。在每个函数中,我进行验证,并返回哪个验证失败。有什么想法吗?

// Ideal Case...

public class MyModel
{
    string Title { get; set; }
    DateTime? Start { get; set; }
    DateTime? End { get; set; }
}

RuleFor(i => i.Start)
            .Must((model,start) => BeValidStartDate(start, model.End));

RuleFor(i => i.End)
            .Must((model,end) => BeValidEndDate(end, model.Start));

public bool BeValidStartDate(DateTime? start, DateTime? end)
{
        // start must come before end
        if (start.Value < end.Value)
        {
            // psuedocode...
            return ValidationMessage("Start must come before end.");
        }

        // other validations...
}

1 个答案:

答案 0 :(得分:1)

您可以使用out修饰符添加第三个参数,并通过以下内容传递消息:

public bool BeValidDatePair(DateTime? start, DateTime? end, out string message)
{
    ...

    if (start.Value < end.Value) message = "Start must come before end.";
}

然后你会这样称呼:

string message = String.Empty;
BeValidDatePair(dateone, datetwo, message);

https://msdn.microsoft.com/en-us/library/t3c3bfhx.aspx

另一种选择可能是抛出自己的异常类型并使用try / catch隐式捕获它们:

public class DateOutOfRangeException : Exception
{
    ...
}

catch (DateOutOfRangeException ex)

然后:

if (start.Value < end.Value) throw new DateOutOfRangeException();

https://msdn.microsoft.com/en-us/library/87cdya3t(v=vs.110).aspx