Model not valid even though no properties have the [Required] attribute

MattNorman

Well-known member
Joined
May 22, 2021
Messages
98
Programming Experience
1-3
I have a user model as follows:

C#:
public sealed class DTOUser
{
    public int UserId { get; set; }

    [Required]
    [Display(Name = "Username (*)")]
    public string Username { get; set; } = null!;

    [Required]
    [JsonIgnore]
    [Display(Name = "Password (*)")]
    public string Password { get; set; } = null!;

    [Required]
    [Display(Name = "First Name (*)")]
    public string FirstName { get; set; } = null!;

    [Required]
    [Display(Name = "Last Name (*)")]
    public string LastName { get; set; } = null!;

    [Required]
    [EmailAddress]
    [Display(Name = "Email (*)")]
    public string Email { get; set; } = null!;

    [Required]
    public bool Locked { get; set; }

    [Required]
    public bool IsTempPassword { get; set; }

    public bool ChangePassword { get; set; }

    public bool IsEdit { get; set; }

    public bool EmailPassword { get; set; }

    [Required]
    [Display(Name = "Role (*)")]
    public int UserRoleId { get; set; }


    // Used to hold select list values for user role.
    public IEnumerable<SelectListItem>? UserRoleSelectList { get; set; }


    // Used to hold users wallet permissions.
    public List<DTOUserWalletPermission> WalletPermissions { get; set; } = new();

    public override string ToString()
    {
        return JsonConvert.SerializeObject(this, Formatting.Indented);
    }
}

This model contains a list of 'DTOUserWalletPermission' which is defined as follows:

C#:
public sealed class DTOUserWalletPermission
{
    public int UserWalletPermissionsId { get; set; }
    public int UserId { get; set; }
    public int WalletId { get; set; }
    public bool AddAccounts { get; set; }
    public bool EditAccounts { get; set; }
    public bool DeleteAccounts { get; set; }

    public string WalletName { get; set; } = null!;
}

I have a table in my view that displays the contents of the 'WalletPermissions' property.

When posting the data back the model state shows as invalid specifically for the 'WalletName' property within the user model. I don't understand this as that property does not have the [Required] attribute. Even if I assign that property a value before checking the model state, it still returns as not valid.

What I am essentially trying to achieve is to have the wallet permission data displayed in a table and allow the three bool values to be changed using checkboxes without the other properties being editable. I can match the missing data back up in the controller but just need the model validation to work correctly.

Can anyone help?
 
Who is doing the validation?
 
I'm guessing the issue is that your have declared WalletName as type string, which indicates that it cannot be null, rather than type string?, indicating that it can be null. Why do you have a null-forgiving operator here:
C#:
public string WalletName { get; set; } = null!;
It seems to me that you are trying to prevent an error or warning without knowing what the actual problem is or what the solution does.
 
I'm guessing the issue is that your have declared WalletName as type string, which indicates that it cannot be null, rather than type string?, indicating that it can be null. Why do you have a null-forgiving operator here:
C#:
public string WalletName { get; set; } = null!;
It seems to me that you are trying to prevent an error or warning without knowing what the actual problem is or what the solution does.
Honestly this is a lack of understanding from switching from .NET Framework to .NET 7 Preview.

When using EF to generate models it creates string properties this way so I have been mirroring it.

I have tried changing it to allow it to be a nullable string however it still comes back as invalid.

Is the ModelState.Valid property evaluated when called or is it automatically evaluated before the rest of the code in the post action? It seems even manually adding data to the property, it is still invalid.
 
It is evaluated before the post action, while the parameters of the post action are being bound.
 
Solution
It is evaluated before the post action, while the parameters of the post action are being bound.
Ok thanks. That makes sense then.

I might have to come up with a different way of binding the data to the table with only some propertied being editable.

I guess an alternative would be to have variations of the model with different validation requirements depending on what type of action is being performed.
 
Make a smaller data transfer object that is made specifically for your view. Do you really need all those other fields if you're view doesn't even use them?
 
Make a smaller data transfer object that is made specifically for your view. Do you really need all those other fields if you're view doesn't even use them?
My view does use most of them to display data but not all of that data is editable. Some of the properties can be dropped and some don't need to be validated so I will take that approach to begin with and just create variants of the model for each view/action type.
 
Also keep in mind that I don't think there is a requirement that the model that you declare for the page necessarily has to be what is sent on the form post. As I recall, there is a variant of the HtmlBeginForm() that lets you pass in an anonymous type as the last parameter. I'm assuming that the binding will attempt to map the fields of that anonymous type into the declare parameter(s) of your method.
 
Back
Top Bottom