0

I'm converting an ASP.NET 4.8 MVC web site to ASP.NET Core 7 MVC. I'm running into a problem with ModelValidation where my ModelState is always valid, even when it is not. I'm using the pattern that was used in .Net 4x and worked fine. Microsoft Learn link

Controller

[HttpPost]
public async Task<IActionResult> Create(TcPhoneType tcPhoneType)
{
    if (ModelState.IsValid)
    {
        await _phoneTypeService.CreatePhoneType(tcPhoneType);
        return RedirectToAction("Index");
    }

    return View(tcPhoneType);
}

Model.cs

// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace App.Models;

public partial class TcPhoneType
{
    public string PhoneTypeId { get; set; }

    public string PhoneTypeDescription { get; set; }

    public virtual ICollection<MemberPhone> MemberPhones { get; } = new List<MemberPhone>();
}

ModelMetadata.cs

using System.ComponentModel.DataAnnotations;

namespace App.Models;

[MetadataType(typeof(TcPhoneTypeMetadata))]
public partial class TcPhoneType
{
}

public class TcPhoneTypeMetadata
{
    [Required(AllowEmptyStrings = false, ErrorMessage = "Item is required")]
    [StringLength(1)]
    public string? PhoneTypeId { get; set; }

    [Required(AllowEmptyStrings = false)]
    [StringLength(5)]
    public string? PhoneTypeDescription { get; set; }
}

Create.cshtml

@model SeasonCourt7.Models.TcPhoneType

@{
    ViewBag.Title = "Add Phone Type Code";
}

<h2>@(ViewBag.Title)</h2>
<br>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <hr />
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="row mb-3">
            <div class="col-sm-2">
                <label asp-for="PhoneTypeId" class="col-form-label">Code</label>
            </div>
            <div class="col-sm-10">
                <input asp-for="PhoneTypeId" class="form-control" autofocus />
            </div>
            <span asp-validation-for="PhoneTypeId" class="text-danger"></span>
        </div>
        <div class="row mb-3">
            <div class="col-sm-2">
                <label asp-for="PhoneTypeDescription" class="col-form-label">Description</label>
            </div>
            <div class="col-sm-10">
                <input asp-for="PhoneTypeDescription" class="form-control" />
            </div>
            <span asp-validation-for="PhoneTypeDescription" class="text-danger"></span>
        </div>
        <div class="row mb-3">
            <div class="offset-sm-2 col-sm-10">
                <input type="submit" value="Create" class="btn btn-primary" />
                <a href="javascript:history.back()" class="btn btn-outline-dark" data-bs-title="Return to previous screen" data-bs-toggle="tooltip" data-bs-placement="top">Back</a>
            </div>
        </div>
    </div>
}


@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

I set a breakpoint on the if (ModelState.IsValid) line so I could inspect the model and ModelState. I can see the data that is bound to the model is as expected and the ModelState is always valid.

If I pass null data in the model, I should see the ModelState.IsValid = false, but it's always true.

The model.cs is generated by EF and could be regenerated in the future which makes it impractical to add the metadata attributes for validation, as the file could be regenerated in the future.

The only way I've been able to get the ModelValidation to work as expected, is to decorate the model directly with the validation attributes.

mcolegro
  • 559
  • 5
  • 18
  • Can you share your view code and more steps? I try to submit null data, but `ModelState.IsValid` is false. – Chen Feb 01 '23 at 09:32
  • I have added the view code. When I run the app and enter data in the form, the data is correctly bound to the model, but the ModelState.IsValid is always true. When I submit null data, I should see ModelState.IsValid == false. – mcolegro Feb 01 '23 at 13:01
  • I used the view code you provided to test, and the test result did not have the problem you said. When submitting null data, JS validation will be triggered, and the controller operation will not be called; when JS validation is canceled, `ModelState.IsValid = false`. – Chen Feb 02 '23 at 01:14
  • Yes, that is the behavior I was expecting. That is how the ModelBinding/ModelValidation worked in .Net 4.x. It doesn't seem to be working that way in .Net 7. – mcolegro Feb 03 '23 at 13:44
  • No, the same applies to .net 7. You could try creating a new .net 7 template, then add the model for validation, and you should get what you expect. Check [this link](https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-7.0). – Chen Feb 06 '23 at 09:30

0 Answers0