How to display specific ModelState errors in ASP.NET Core MVC?

Mkalafut

In one of my controller actions, the first thing I do is pass the model to a new action that essentially just parses input to determine whether or not the user entered a valid date. The model is then returned and ModelState.IsValid is inspected.

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;
    }

At the point where I know I have model state errors, I am able to correctly show them in my razor view by putting the following

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

So, since all of my model state errors are for the same input on the page I can safely do this. But what if I have various inputs with various errors that I need to display independently of one another? How would I go about doing this? Additionally, is there a better (or more appropriate) way to do this aside from using @Html.ValidationSummary?

I have searched through Microsoft docs and a few dozen StackOverflow questions to try and translate older answers into the .Net Core way of doing things with no luck.

Edit for clarity:

Here is the entire card in the razor view:

<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>

The input is for a model property however it is not annotated. I've written my own rules and manually add errors to the model state if the rules are not adhered to. The code I have works however it's not scalable when I start needing to validate more fields. I just want to know what a better way of doing this is.

ADyson

In the example above, you are not really following standard practice.

For simple validations like this (where you're only validating the value in one field) the key you use to place the error message against in the ModelState is supposed to be the same as the name of the affected field in the model. In your case, really all your errors should be logged against the CurrMoInfo.CurrMo key. Only the error message itself needs to differ. Using a custom key for each specific different error doesn't add any value to your application as far as I can tell. You're not using it the way it was intended.

If you log them all against CurrMoInfo.CurrMo then you can use an asp-validation-for tag helper to create a field which displays errors specifically for that field, e.g.

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

You can then (optionally) use a ValidationSummary to (as the title suggests) summarise all the errors for the whole model - and to display any extra model errors you may have created which don't relate to a single specific field.

Complete example:

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>

Further reading: https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/validation?view=aspnetcore-2.2

P.S. I don't think this general principle has changed from .NET Framework to .NET Core.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to get all Errors from ASP.Net MVC modelState?

How to display errors with ASP.NET Core

How do I include a clickable hyperlink in ASP.NET MVC Core ModelState error message?

Globally ModelState Validation In Asp.Net Core Mvc

How to properly handle AJAX errors in ASP.NET Core MVC?

ASP.NET MVC: how to add nested property to Modelstate?

ASP.NET MVC ModelState how to re-run validation

How to keep using ModelState with RedirectToAction in ASP.NET MVC 6?

ASP.NET display ModelState.AddModelError

ModelState Validation not working asp.net MVC

How to trace errors in asp.net core

ASP.NET MVC Core 3.0 - Why API Request from body keeps returning !ModelState.IsValid?

ASP.NET Core MVC: Order Navigation Property is Null When Creating Item, Resulting in Invalid ModelState

ModelState IsValid returns False Using ASP.NET Core 5 MVC Identity with UserName

ModelState.IsValid always returns false in ASP.NET Core 6.0 MVC

How to handle errors differently for (or distinguish between) API calls and MVC (views) calls in ASP.NET Core

ASP.NET Core 7 MVC model errors on modal popup

How to Rebind MVC Core 2 ModelState

How to display Enum as DropDownList in .Net MVC Core

How can I display specific range of items in an ASP.NET MVC view passed from ViewBag in array

How to display alert message box in asp.net core mvc controller?

How do I use post method to display a content in ASP.net core MVC

ASP.NET Core MVC - How to display data from Excel into HTML table before inserting into the DB

How to display data from one View to another ASP.NET CORE 5.0 MVC

How do I get the user id from my database and display it using ASP.NET Core MVC

How to directly display login screen on welcome/start page in ASP.NET Core 6 MVC app?

How display content created by specific user using ASP.NET Core, Identity Framework with Entity Framework

How can I stop ASP.NET Core 2.0 MVC minification from modifying a specific file?

How to query a column in a database based on specific value MVC ASP.NET Core

TOP Ranking

HotTag

Archive