Search code examples
c#.netasp.net-mvcentity-frameworkdata-annotations

Data.Annotations like required and regularexpression not working on certain model


I can't seem to make the [Required] and [RegularExpression] data annotation to work on a certain model. On all other models it does work. When I do not enter any information in the fields of Address.cshtml, it still accepts it, and sends it to the database. On all other pages where required is used, it does work. So I must do something wrong I guess.

Address.cshtml.cs is where the InputModel is with the required fields.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using bytme.Models;
using bytme.Data;

namespace bytme.Areas.Identity.Pages.Account.Manage
{
    public class AddressModel : PageModel
    {
        private readonly UserManager<UserModel> _userManager;
        private readonly SignInManager<UserModel> _signInManager;
        private readonly ILogger<AddressModel> _logger;
        private readonly ApplicationDbContext _context;

        public AddressModel(
            UserManager<UserModel> userManager,
            SignInManager<UserModel> signInManager,
            ILogger<AddressModel> logger,
            ApplicationDbContext context)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _logger = logger;
            _context = context;
        }

        [BindProperty]
        public InputModel Input { get; set; }

        public string ReturnUrl { get; set; }

        [TempData]
        public string StatusMessage { get; set; }

        public class InputModel
        {
            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Name")]
            [StringLength(100, ErrorMessage = "Invalid input. Maximum is 100 characters.")]
            public string name { get; set; }

            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Surname")]
            [StringLength(100, ErrorMessage = "Invalid input. Maximum is 100 characters.")]
            public string surname { get; set; }

            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "Street")]
            [StringLength(48, ErrorMessage = "The longest street name in the Netherlands is 48 characters.")]
            public string street { get; set; }

            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "House Number")]
            [StringLength(5, ErrorMessage = "The longest house number in the Netherlands is 5 characters.")]
            public string streetnumber { get; set; }

            //[DataType(DataType.Text)]
            //[Display(Name = "House Number Addition", Description = "For example A or II")]
            //[StringLength(6, ErrorMessage = "
            //public string streetnumberadd { get; set; }

            [Required]
            [DataType(DataType.Text)]
            [Display(Name = "City")]
            [StringLength(28, ErrorMessage = "The longest place name in the Netherlands is 28 characters.")]
            public string city { get; set; }

            [Required]
            [DataType(DataType.PostalCode)]
            [Display(Name = "Postal Code")]
            [RegularExpression(@"^[1-9][0-9]{3}\s?[a-zA-Z]{2}$", ErrorMessage = "Invalid zip, for example: 1234AB")]
            public string zipcode { get; set; }
        }

        public void OnGet(string returnUrl = null)
        {
            ReturnUrl = returnUrl;
        }

        public async Task<IActionResult> OnPostAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user == null)
            {
                throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
            }

            user.name = Input.name;
            user.surname = Input.surname;
            user.street = Input.street;
            user.streetnumber = Input.streetnumber;
            user.city = Input.city;
            user.zipcode = Input.zipcode;

            var changeAdresResult = _context.Users.Update(user);
            _context.SaveChanges();

            await _signInManager.SignInAsync(user, isPersistent: false);
            _logger.LogInformation("User added their address information successfully.");
            StatusMessage = "Your address information has been added.";

            return RedirectToPage();



        }
    }
}

Address.cshtml is where the fields are made.

@page
@model AddressModel
@inject SignInManager<UserModel> SignInManager
@using Microsoft.AspNetCore.Identity
@using bytme.Models;
@{
    ViewData["Title"] = "Add Address Information";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@{
    var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<div>
    <h3>Change your account settings</h3>
    <hr />
    <div class="row">
        <div class="col-md-3">
            <partial name="_ManageNav" />
        </div>
        <div class="col-md-9">
            <div class="row">
                <div class="col-md-6">
                    <partial name="_StatusMessage" for="StatusMessage" />
                    <h4>@ViewData["Title"]</h4>
                    <form id="change-password-form" method="post">
                        <div asp-validation-summary="All" class="text-danger"></div>
                        <div class="form-group">
                            <label asp-for="Input.name"></label>
                            <input asp-for="Input.name" class="form-control" />
                            <span asp-validation-for="Input.name" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label asp-for="Input.surname"></label>
                            <input asp-for="Input.surname" class="form-control" />
                            <span asp-validation-for="Input.surname" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label asp-for="Input.street"></label>
                            <input asp-for="Input.street" class="form-control" />
                            <span asp-validation-for="Input.street" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label asp-for="Input.streetnumber"></label>
                            <input asp-for="Input.streetnumber" class="form-control" />
                            <span asp-validation-for="Input.streetnumber" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label asp-for="Input.city"></label>
                            <input asp-for="Input.city" class="form-control" />
                            <span asp-validation-for="Input.city" class="text-danger"></span>
                        </div>
                        <div class="form-group">
                            <label asp-for="Input.zipcode"></label>
                            <input asp-for="Input.zipcode" class="form-control" />
                            <span asp-validation-for="Input.zipcode" class="text-danger"></span>
                        </div>
                        <button type="submit" class="btn btn-default">Submit</button>
                    </form>
                </div>
            </div>

        </div>
    </div>
</div>

EDIT:

I noticed when editing the OnPostAsync to another name, for example AccountChange, that the data annotations do work. But I do need the OnPostAsync on the method, because on the view I use method="post", otherwise I can't send the information to the database.


Solution

  • I think you need to do your validation in OnPostAsync:

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();  // <-- model error
        }
    
        // continue with your post logic...
    

    See here