Search code examples
entity-framework-6razor-pages

DateOnly field not being populated from form .NET6 EF6 Razor Pages No MVC


For some reason the dates that I enter in the date-type inputs of the form are not getting into the database. Instead, after all the different methods I researched and tried, to no avail, the dates default to 01/01/01, which I understand to be the defualt min value yes? And in the postgres database, the date fields show "-infinity". I can use pgadmin query tool to update the dates successfully, but when I try to create or edit a record from the form, the above occurs.

When I get to the ModelState.IsValid line in the debugger, it is showing the data I entered correctly in the other fields, but the date fields are showing 01/01/01.

I have been through the docs and other forum posts but none of the fixes I attempted worked. Any help would be greatly appreciated.

Here is the model

 public class ToDo
    {
        [Key]
        public int Id { get; set; }

        public DateOnly CreateDate { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        public string Description { get; set; }

        public DateOnly DueDate { get; set; }

        public bool Complete { get; set; }

    }

... the post

public async Task<IActionResult> OnPost()

{

    if (!ModelState.IsValid)
    {
        var errors = ModelState.SelectMany(x => x.Value.Errors.Select(z => z.Exception));
    }

    if (ModelState.IsValid)
    {
        await _db.Todo.AddAsync(Todo);
        await _db.SaveChangesAsync();
        TempData["success"] = "ToDo created successfully.";
        return RedirectToPage("Index");
    }
    return Page();
}

... and the form

<form method="post">
    <input hidden asp-for="Todo.Id" />
    <div class="p-3 mt-4">
        <div class="row pb-2">
            <h2 class="text-primary pl-3">Create ToDo</h2>
            <hr />
        </div>
        <div asp-validation-summary="All"></div>
        <div class="mb-3">
            <label asp-for="@Model.Todo.CreateDate"></label>
            <input asp-for="@Model.Todo.CreateDate" class="form-control"  type="date"/>
            <span asp-validation-for="Todo.CreateDate" class="text-danger"></span>
        </div>
        <div class="mb-3">
            <label asp-for="@Model.Todo.Name"></label>
            <input asp-for="@Model.Todo.Name" class="form-control" />
            <span asp-validation-for="Todo.Name" class="text-danger"></span>
        </div>
        <div class="mb-3">
            <label asp-for="@Model.Todo.Description"></label>
            <input asp-for="@Model.Todo.Description" class="form-control" />
            <span asp-validation-for="Todo.Description" class="text-danger"></span>
        </div>
        <div class="mb-3">
            <label asp-for="@Model.Todo.DueDate"></label>
            <input asp-for="@Model.Todo.DueDate" class="form-control"  type="date"/>
            <span asp-validation-for="Todo.DueDate" class="text-danger"></span>
        </div>
        <div class="form-check m-4">
            <input asp-for="@Model.Todo.Complete" class="form-check-input" type="checkbox"/>
            <label class="form-check-label ms-3" asp-for="@Model.Todo.Complete">
            Complete
            </label>
        </div>
        <button type="submit" class="btn btn-outline-primary rounded-pill" style="width:150px;">Update</button>
        <a asp-page="Index" class="btn btn-outline-secondary rounded-pill text-white" style="width:150px;">Back To List</a>
    </div>
</form>

Solution

  • You are using the new DateOnly type. The ASP.NET Core model binder does not support binding to DateOnly at the moment (https://github.com/dotnet/aspnetcore/issues/34591). Until .NET 7, you can use a DateTime type and data annotations to control the input type that gets rendered (https://www.learnrazorpages.com/razor-pages/forms/dates-and-times):

    [DataType(DataType.Date)]
    public DateTime CreateDate { get; set; }
    

    Alternatively, you can extract the value from Request.Form yourself and assign it to the relevant property:

    if(DateTime.TryParse(Request.Form["Todo.CreateDate"].ToString(), out var created))
    {
        Todo.CreateDate = DateOnly.FromDateTime(created);
    }
    else
    {
        ModelState.AddModelError("Todo.CreateDate", "A created date must be a date");
    }