Search code examples
c#asp.net-corerazor-pages

Razor Page validation error with a complex object, TryValidateModel() does not work


I am building .Net 5 Razor Pages Web App and have a structure with two objects:

public class Location
{
    public Guid Id { get; set; }

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

    [Required]
    [ForeignKey("Organization")]
    public Guid OrganizationId { get; set; }

    public Organization Organization { get; set; }
}

public class Organization
{
   public Guid Id { get; set; }

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

Here are fields from my Razor Page to edit Location objects:

<input asp-for="Location.Organization.Id" class="hidden" value="@Model.Location.Organization.Id" />
<input asp-for="Location.Id" class="hidden" value="@Model.Location.Id" />
<input asp-for="Location.Name" class="form-control" value="@Model.Location.Name" />

I don't have fields for the Organization object on the page.

In the OnPost() method I fill the Organization object from my Database and try to validate the model again.

Location.Organization = await _db.Organizations.FindAsync(Location.Organization.Id);

if (!TryValidateModel(Location, nameof(Location)))
{   
    return Page();
}

But it does not work. The Model is still invalid (ModelState.IsValid != true)

The Validation Error says Organization.Name should be filled.

But all the fields in the Location object are filled correctly. After filling the Organization object, the Organization.Name field is also filled with not empty string and should pass the validation.

I am fighting with the problem for hours and have already tried to do it other ways, like TryValidateModel(Location.Organization) and so on.

I am looking for a way to do it without placing the Organization.Name field in the form. Since I have much more other fields in my real Organization object, I don't want to put they all in the form. I also don't want to ignore validation errors.

I am trying currently to understand how TryValidateModel() works, but it is not quite simple to find out from the source code.

Any ideas how to fix the problem?


Solution

  • You can try to add ModelState.Clear before TryValidateModel(Location, nameof(Location)).Here is a demo:

    cshtml.cs:

    [BindProperty]
            public Location Location { get; set; }
            public void OnGet()
            {
                Location = new Location { Id = Guid.NewGuid(), Name = "loc", Organization = new Organization { Id = Guid.NewGuid() } };
            }
            public IActionResult OnPost()
            {
                Location.Organization = new Organization { Id = Location.Organization.Id, Name = "org" };
                ModelState.Clear();
                if (!TryValidateModel(Location, nameof(Location)))
                {
                    return Page();
                }
                else {
                    var s = ModelState.IsValid;
                    return Page();
                }
            }
    

    result: enter image description here