【问题标题】:How to display specific ModelState errors in ASP.NET Core MVC?如何在 ASP.NET Core MVC 中显示特定的 ModelState 错误?
【发布时间】:2019-10-21 00:53:30
【问题描述】:

在我的一个控制器操作中,我做的第一件事是将模型传递给一个新操作,该操作基本上只是解析输入以确定用户是否输入了有效日期。然后返回模型并检查 ModelState.IsValid。

public Import ValidateUploadModel(Import Model)
    {
        // DO not allow future dates
        if (Model.CurrMoInfo.CurrMo > DateTime.Now)
        {
            ModelState.AddModelError("FutureDate", "You cannot assign a future date.");
        }
        //Do not allow dates from the same month (we run the processing a month behind)
        if (Model.CurrMoInfo.CurrMo.Month == DateTime.Now.Month)
        {
            ModelState.AddModelError("SameMonth", "You must process a previous month.");
        }

        //Ensure day is last day of a previous month
        if (Model.CurrMoInfo.CurrMo.Day != DateTime.DaysInMonth(Model.CurrMoInfo.CurrMo.Year, Model.CurrMoInfo.CurrMo.Month))
        {
            ModelState.AddModelError("LastDay", "You must enter the last day of the month.");
        }

        //Do not allow dates older than 12 months back
        if (Model.CurrMoInfo.CurrMo < DateTime.Now.AddMonths(-12))
        {
            ModelState.AddModelError("TooOld", "Date must not be older than a year.");
        }

        return Model;
    }

当我知道我有模型状态错误时,我可以通过输入以下内容在我的剃刀视图中正确显示它们

<span class="text-danger">@Html.ValidationSummary(false)</span>

所以,由于我所有的模型状态错误都是针对页面上的相同输入的,所以我可以安全地执行此操作。 但是,如果我有各种错误的输入需要相互独立地显示呢?我该怎么做呢?此外,除了使用@Html.ValidationSummary 之外,还有更好(或更合适)的方法吗?

我搜索了 Microsoft 文档和几十个 StackOverflow 问题,试图将较旧的答案翻译成 .Net Core 的做事方式,但没有成功。

为清楚起见进行编辑:

这是剃刀视图中的整张卡片:

<div class="card-body">

                @if (Model.StagingCount == 0)
                {
                    <input asp-for="@Model.CurrMoInfo.CurrMo" type="date" required class="col-lg-12" />
                }
                else
                {
                    <input asp-for="@Model.CurrMoInfo.CurrMo" type="date" disabled="disabled" required class="col-lg-12" />
                }

                <span class="text-danger">@Html.ValidationSummary(false)</span>

            </div>

输入用于模型属性,但没有注释。如果不遵守规则,我已经编写了自己的规则并手动将错误添加到模型状态。我的代码可以工作,但是当我开始需要验证更多字段时它是不可扩展的。我只是想知道这样做的更好方法是什么。

【问题讨论】:

  • 这显示了如何为各个字段放置验证消息。例如&lt;span asp-validation-for="FutureDate" class="text-danger"&gt;&lt;/span&gt;
  • 如果您事先知道要显示哪些模型字段(即您没有在 AddModelError 方法中定义任意或动态生成的键),那么您可以使用带有asp-validation-for 标签助手的控件他们。这些将用作在生成特定错误消息时显示特定错误消息的地方。更多详情请见docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/…
  • @ADyson 在这种情况下,模型没有注释,我只是在控制器中的方法中创建自己的错误。 asp-validation-for 在这里不起作用,因为错误是专门添加到 ModelState 中的。

标签: c# asp.net-core model-view-controller asp.net-core-mvc asp.net-core-2.2


【解决方案1】:

在上面的示例中,您并没有真正遵循标准做法。

对于像这样的简单验证(您只验证一个字段中的值),用于在 ModelState 中放置错误消息的键应该与模型中受影响字段的名称相同.在您的情况下,实际上您的所有错误都应该记录在 CurrMoInfo.CurrMo 键上。只有错误消息本身需要不同。据我所知,为每个特定的不同错误使用自定义键不会为您的应用程序增加任何价值。您没有按照预期的方式使用它。

如果您将它们全部记录在 CurrMoInfo.CurrMo 上,那么您可以使用 asp-validation-for 标签助手创建一个字段,专门显示该字段的错误,例如

<span asp-validation-for="CurrMoInfo.CurrMo" class="text-danger"></span>

然后,您可以(可选)使用 ValidationSummary 来(如标题所示)汇总整个模型的所有错误 - 并显示您可能创建的与单个特定字段无关的任何额外模型错误。

完整示例:

public Import ValidateUploadModel(Import Model)
{
    // DO not allow future dates
    if (Model.CurrMoInfo.CurrMo > DateTime.Now)
    {
        ModelState.AddModelError("CurrMoInfo.CurrMo", "You cannot assign a future date.");
    }
    //Do not allow dates from the same month (we run the processing a month behind)
    if (Model.CurrMoInfo.CurrMo.Month == DateTime.Now.Month)
    {
        ModelState.AddModelError("CurrMoInfo.CurrMo", "You must process a previous month.");
    }

    //Ensure day is last day of a previous month
    if (Model.CurrMoInfo.CurrMo.Day != DateTime.DaysInMonth(Model.CurrMoInfo.CurrMo.Year, Model.CurrMoInfo.CurrMo.Month))
    {
        ModelState.AddModelError("CurrMoInfo.CurrMo", "You must enter the last day of the month.");
    }

    //Do not allow dates older than 12 months back
    if (Model.CurrMoInfo.CurrMo < DateTime.Now.AddMonths(-12))
    {
        ModelState.AddModelError("CurrMoInfo.CurrMo", "Date must not be older than a year.");
    }

    return Model;
}


<div class="card-body">
    @if (Model.StagingCount == 0)
    {
        <input asp-for="CurrMoInfo.CurrMo" type="date" required class="col-lg-12" />
    }
    else
    {
        <input asp-for="CurrMoInfo.CurrMo" type="date" disabled="disabled" required class="col-lg-12" />
    }
    <span asp-validation-for="CurrMoInfo.CurrMo" class="text-danger"></span>
</div>

延伸阅读:https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/validation?view=aspnetcore-2.2

附:我不认为这个一般原则从 .NET Framework 到 .NET Core。

【讨论】:

  • 谢谢。有了这个答案和你的 cmets,你给了我很多很好的信息,并纠正了我对它应该如何工作的一些误解。这是一个很好的解决方案。
  • @Mkalafut 没问题。但我会更谦虚,它与其说是一个“伟大”的解决方案,不如说是一个简单的“标准”解决方案:-)。不管怎样,很高兴它帮助你理解了这些概念。
  • 我已经将我所有的 ModelState.AddModelError 调用更改为现在都具有相同的键 CurrMoInfo.CurrMo 并且它按描述正确工作,除了如果添加了两个错误,则只显示一个.另外,这是一种可接受的方法还是我应该找到一种方法将这些作为注释添加到我的模型属性上? (如果是这样,我将如何制作这样的自定义注释而不是在控制器操作中进行?)
  • “我是否应该找到一种方法将这些作为注释添加到我的模型属性中”。这不是必需的,不。你的方法基本没问题。如果您有可能应用于其他字段的规则(例如比较两个日期),那么您可以考虑编写自己的自定义属性以使其可重用。或者,有 NugetPackages(例如 FluentValidation、FoolproofValidation、ExpressiveAnnotations 等)旨在使您可以在注释规则中编写比默认情况下更强大的表达式。你也许可以看看那些。
  • 看到你的更新。所以......“如果添加了两个错误,则只显示一个”......是的,我认为不幸的是这种情况。如果您使用注释,那么我相当确定您可以同时显示多个错误 - 当然至少对于客户端验证(因为您目前只有服务器端验证,这不适用)。一个快速的 google 发现有人重写了标记帮助程序代码(至少在 .NET Framework 中,不确定 .NET Core)以使其一次显示多个(服务器端)错误。恕我直言,这是一个愚蠢的限制,但你去吧,我没有写它:-)
猜你喜欢
  • 2013-06-07
  • 1970-01-01
  • 2020-11-23
  • 2011-03-09
  • 1970-01-01
  • 2011-06-06
  • 2010-11-24
  • 2011-02-20
  • 1970-01-01
相关资源
最近更新 更多