需要一个或另一个字段

Require one field or another

基本上我想弄清楚的是如何要求在视图中至少填写两个字段之一。

在我的视图中,我有两个名为 ISBN 和 ISBN13 的文本字段。用户填哪一个都无所谓,填其中一个即可。

我不确定在这里该做什么期望研究编写自定义验证器所以我想我会先问。我会包含一些代码,但由于它只是两个简单的字段,我认为这个解释会更好。

我想在将更改保存到数据库之前,在创建部分中将类似这样的内容添加到您的控制器中。

int countISBN = Product.ISBN.Count() + Product.ISBN13.Count();
if (countISBN <= 9)
{
    // Add in an error message.
    return View();
}

这将做的是计算两个字段中的字符,并将它们相加。如果它们的总和低于 10,则会抛出错误。

使用 MVC Foolproof NuGet 包,然后您可以使用 RequiredIf 属性,如下所示:

[RequiredIf("ISBN==\"\"")] // backslash is used for escaping the quotes
public string ISBN13 { get; set; }

[RequiredIf("ISBN13==\"\"")]
public string ISBN { get; set; }

您可以在控制器操作中进行手动验证。 AddModelError 方法将帮助您使用验证堆栈。

[HttpPost]
public ActionResult Edit(EditModel model)
{
    if (string.IsNullOrEmpty(model.ISBN) && string.IsNullOrEmpty(model.ISBN13))
    {
        var validationMessage = "Please provide ISBN or ISBN13.";
        this.ModelState.AddModelError("ISBN", validationMessage);
        this.ModelState.AddModelError("ISBN13", validationMessage);
    }

    if (!string.IsNullOrEmpty(model.ISBN) && !string.IsNullOrEmpty(model.ISBN13))
    {
        var validationMessage = "Please provide either the ISBN or the ISBN13.";
        this.ModelState.AddModelError("ISBN", validationMessage);
        this.ModelState.AddModelError("ISBN13", validationMessage);
    }

    if (this.ModelState.IsValid)
    {
        // do something with the model
    }

    return this.View(model);
}

有些人可能会说,控制器不负责对查询进行验证。我认为控制器的职责是将网络请求适配为域请求。因此,控制器可以有验证逻辑。如果你没有 domain/business 层,这个考虑就没有意义。

.net 框架:万无一失

.net 核心:FoolProof.Core

[RequiredIfEmpty] 存在于新版本中。例如:

    [RequiredIfEmpty(dependentProperty: "ISBN", DependentPropertyDisplayName = "ISBN", ErrorMessage = "If ISBN is null then ISBN13 is require")]

还有很多其他属性:

[RequiredIf]
[RequiredIfNot]
[RequiredIfTrue]
[RequiredIfFalse]
[RequiredIfEmpty]
[RequiredIfNotEmpty]
[RequiredIfRegExMatch]
[RequiredIfNotRegExMatch]

要查看参考,请单击 this link

有了数据注释,如果您想避免第三方,我认为这是一个不错的选择。跳过必需的属性并在仅具有 getter 的 属性 上设置规则:

public class EditModel
{
    public string ISBN { get; set; }
    public string ISBN13 { get; set; }
    
    [Range(1, Double.MaxValue, ErrorMessage = "At least one field must be given a value")]
    public int Count
    {
        get
        {
            var totalLength = 0;
            totalLength += ISBN?.Length ?? 0;
            totalLength += ISBN13?.Length ?? 0;
            return totalLength;
        }
    }
}

对于其他数据类型,并具有特定属性,它可以像这样工作:

public class EditModel
{
    [MinLength(10)]
    public string ISBN { get; set; }
    [MinLength(13)]
    public string ISBN13 { get; set; }
    [MinLength(1)]
    public List<Guid> ISBNItems { get; set; }
    [Range(1, 100)]
    public int? SomeNumber { get; set; }
    
    [Range(1, Double.MaxValue, ErrorMessage = "At least one field must be given a value")]
    public int Count
    {
        get
        {
            var totalLength = 0;
            totalLength += ISBN?.Length ?? 0;
            totalLength += ISBN13?.Length ?? 0;
            totalLength += ISBNItems?.Count ?? 0;
            totalLength += SomeNumber ?? 0;
            return totalLength;
        }
    }
}

编辑:我想到了另一种方法,我将 Count-属性 替换为:

[RegularExpression("True|true", ErrorMessage = "At least one field must be given a value")]
public bool Any => ISBN != null || ISBN13 != null;

基本上是一样的,只是一个 getter 检查属性是否为空。