How to use BindingResult Thymeleaf validation? - thymeleaf

I have a bit issue related to binding result thymeleaf validation.
on form submit with empty string binding result is not validate.
please you help me to check and advise me what should I fix this issue.
Thank!!
UserDTO
#Entity
public class UserDTO {
#Id
#NotEmpty(message = "First Name is required!!")
private String firstName;
#NotEmpty(message = "Last Name is required!!")
private String lastName;
#NotEmpty(message = "Username is required!!")
private String username;
#NotEmpty(message = "Password is required!!")
private String password;
#NotEmpty(message = "Confirm password is required!!")
private String confirmPassword;
#NotEmpty(message = "Role is required!!")
private String authentication;
//setter getter
Controller
#PostMapping(value = "/addUser")
public String saveUser(#Valid #ModelAttribute("userDTO") UserDTO userDTO, BindingResult
bindingResult, ModelMap model) {
if (bindingResult.hasErrors()) {
return "createUser";
}
User userDb = userRepo.findUserByUsername(userDTO.getUsername());
if (userDb != null) {
throw new RuntimeException("User already exist.");
CreateUser.html
<form th:action="#{/addUser}" class="form-horizontal"
novalidate="novalidate" th:object="${userDTO}" method="post">
<div class="form-body">
<div class="form-group">
<label class="control-label col-md-3">Fist Name
<span class="required" aria-required="true"> * </span></label>
<div class="col-md-4">
<input type="text" th:field="*{firstName}" th:value="null"
data-required="1" class="form-control">
<span th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}">First Name is required!</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Last Name
<span class="required" aria-required="true"> * </span>
</label>
<div class="col-md-4">
<input type="text" th:field="*{lastName}"
data-required="1" class="form-control">
<span th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">Last Name is required!</span>
</div>
</div>

Related

.NET 6 Kendo UI form validations using kendo-rules attribute

I am new to kendo UI. Trying to validate my form using custom rules with kendo-rules attributes. I am referring to this link https://demos.telerik.com/aspnet-core/validator . The custom rules are working but somehow the validation message is getting triggered on different controls.
I am trying to set the custom rule on my "FirstName" field. If "FirstName" field has value less than 5 characters then, validation message "First name cannot be less than 5 characters" should come, for "FirstName" field.
However, I am getting the validation messages on different controls. Refer to the snapshot below.
The expected behaviour is , first required field error should come and then if the user enters first name value less than 5 characters then this "First name cannot be less than 5 characters" error should come.
Here is my code:
Create.cshtml
#model KendoFormValidation_Demo.Models.Person
#{
ViewData["Title"] = "Create";
}
#{
var messages = new Dictionary<string, string>() { { "custom", "First name cannot be less than 5 characters" } };
var rules = new Dictionary<string, string>() { { "custom", "customFunction" } };
}
<div class="row">
<div class="col-md-4">
<form id="PersonForm" kendo-validator="true" kendo-messages="messages" kendo-rules="rules">
<div class="form-group">
<label asp-for="FirstName"></label>
<input asp-for="FirstName" class="form-control" />
<span class="text-danger k-invalid-msg" data-for="FirstName"></span>
</div>
<div class="form-group">
<label asp-for="LastName"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger k-invalid-msg" data-for="LastName"></span>
</div>
<div class="form-group">
<label asp-for="Age"></label>
<input class="form-control" for="Age" />
<span asp-validation-for="Age" class="text-danger k-invalid-msg" data-for="Age"></span>
</div>
<div class="form-group">
<label asp-for="Address"></label>
<input asp-for="Address" class="form-control" />
<span asp-validation-for="Address" class="text-danger k-invalid-msg" data-for="Address"></span>
</div>
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger k-invalid-msg" data-for="Email"></span>
</div>
<div class="form-group">
<label asp-for="Phone"></label>
<input asp-for="Phone" class="form-control" />
<span asp-validation-for="Phone" class="text-danger k-invalid-msg" data-for="Phone"></span>
</div>
<div class="form-group">
<label asp-for="Dob"></label>
<input asp-for="Dob" class="form-control kendo-date-picker" />
<span asp-validation-for="Dob" class="text-danger k-invalid-msg" data-for="Dob"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="k-button k-button-md k-rounded-md k-button-solid-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index" class="k-button k-button-md k-rounded-md k-button-solid">Back to List</a>
</div>
<script>
function customFunction(input) {
debugger;
return input.attr('name') === "FirstName" && input.length<5;
}
$(document).ready( function () {
$(".kendo-date-picker").each(function(){
$(this).kendoDatePicker({
format: "MM/dd/yyyy",
dateInput: true,
value: $(this).val()
}).data('kendoDatePicker')._dateInput.setOptions({
messages:{
"year": "yyyy",
"month": "mm",
"day": "dd"
}
});
});
var validator = $("#PersonForm").data("kendoValidator");
$("form").submit(function(event) {
event.preventDefault();
if (validator.validate()) {
alert("Success");
} else {
alert("fail");
}
});
});
</script>
Person.cs
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
[DataType(DataType.Date)]
public DateTime Dob { get; set; }
}
I am using .Net 6 and Telerik version: ASP.NET Core R2 2022 SP1
Can anybody help me on this? Did I miss anything here.
Thank You

ModelState IsValid returns False Using ASP.NET Core 5 MVC Identity with UserName

I'm trying to accomplish login functionality using UserName instead of Email to Login.
I'm using Bootstrap Modal dialog for loging in users with jquery and ajax for error handling.
The UserName is not an email address so ModelState IsValid always returns false. If I hard code an email address in the javascrip file then all works.
Is there anyway around this issue. Any help would be much appreciated.
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Login</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="UserLoginForm" asp-controller="UserAuth" asp-action="login">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="LoginInValid" />
<div class="form-group row mb-3">
<label asp-for="UserName" class="col-md-4 col-form-label"></label>
<div class="col-md-8">
<input asp-for="UserName" placeholder="User Name" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>
</div>
<div class="form-group row mb-3">
<label asp-for="Password" class="col-md-4 col-form-label"></label>
<div class="col-md-8">
<input asp-for="Password" placeholder="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group-row">
<div class="col-md-8 offset-md-4">
<div class="form-check">
<input asp-for="RememberMe" class="form-check-input" />
<label asp-for="RememberMe" class="col-md-4" col-form-label"></label>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" id="login" name="login" class="btn btn-primary">Login</button>
</div>
</div>
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginModel loginModel)
{
loginModel.LoginInValid = "true";
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(loginModel.UserName, loginModel.Password, loginModel.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
loginModel.LoginInValid = "";
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt");
}
}
return PartialView("_UserLoginPartial", loginModel);
}
Error handling is not displayed
(function () {
var userloginButton = $("#UserLoginModal button[name='login']").click(onUserLoginClick);
function onUserLoginClick() {
var url = "UserAuth/Login";
var antiForgeryToken = $("#UserLoginModal input[name='__RequestVerificationToken']").val();
var username = $("#UserLoginModal input[name = 'UserName']").val();
var email = "mydomain.com"
/*var email = $("#UserLoginModal input[name = 'Email']").val();*/
var password = $("#UserLoginModal input[name = 'Password']").val();
var rememberMe = $("#UserLoginModal input[name = 'RememberMe']").prop('checked');
var userInput = {
__RequestVerificationToken: antiForgeryToken,
UserName: username,
Email: email,
Password: password,
RememeberMe: rememberMe
};
}
});
LoginModel
public class LoginModel
{
[Required]
[Display(Name = "User Name")]
[StringLength(25, MinimumLength = 2)]
public string UserName { get; set; }
[Required]
[StringLength(100, MinimumLength = 2)]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength (100, MinimumLength = 2)]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
public string LoginInValid { get; set; }
}
LoginModel has UserName, Email, and Password all marked as "Required", so ModelState will not be valid unless all are provided.
You'll need to either provide values for each of these (I don't see any Email input in your HTML markup) or remove the [Required] annotation from the LoginModel properties you don't want to provide.

Model binding null values in MVC Core

I am trying to post data from form to action method but looks like model binder is not binding to the entities and I am getting null values in the action method, your help is much appreciated
please find the code snippet below.
Action method
[HttpPost]
public async Task<IActionResult> Update(EditRoleViewModel model)
{
if (ModelState.IsValid)
{
var role = await _Roleame.FindByIdAsync(model.Id);
if (role == null)
{
return RedirectToAction("notfound");
}
role.Name = model.RoleName;
var result = await _Roleame.UpdateAsync(role);
if (result.Succeeded)
{
return RedirectToAction("getAllRoles", "Administrator");
}
}
else {
ModelState.AddModelError(string.Empty, "Error");
}
return View();
}
Model
public class EditRoleViewModel
{
public EditRoleViewModel()
{
names = new List<string>();
}
public string Id;
[Required]
public string RoleName;
public List<string> names;
}
View
#model FirstCoreApplication.Model.EditRoleViewModel
<script src="~/twitter-bootstrap/js/bootstrap.js"></script>
<link href="~/twitter-bootstrap/css/bootstrap.css" rel="stylesheet" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
#{
ViewBag.Title = "Edit Role";
}
<h1>Edit Role</h1>
<form method="post" class="mt-3" asp-controller="Administrator" asp-action="Update">
<div class="form-group row">
<label asp-for="Id" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Id" disabled class="form-control">
</div>
</div>
<div class="form-group row">
<label asp-for="RoleName" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="RoleName" class="form-control">
<span asp-validation-for="RoleName" class="text-danger"></span>
</div>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Update</button>
<a asp-action="ListRoles" class="btn btn-primary">Cancel</a>
</div>
</div>
<div class="card">
<div class="card-header">
<h3>Users in this role</h3>
</div>
<div class="card-body">
#if (Model.names.Any())
{
foreach (var user in Model.names)
{
<h5 class="card-title">#user</h5>
}
}
else
{
<h5 class="card-title">None at the moment</h5>
}
</div>
<div class="card-footer">
Add Users
Remove Users
</div>
</div>
</form>
enter code here
I've spent couple of hours looking for an error in my code and the reason for the binder not working in my case was using a model with public fields rather than public properties:
public class EditRoleViewModel
{
public EditRoleViewModel()
{
names = new List<string>();
}
public string Id { get; set; }
[Required]
public string RoleName { get; set; }
public List<string> names { get; set; }
}
The form data you post does not match the property of your model.You do not post the parameter names .
public List names { get; set; }

InvalidOperationException: The model item passed into the ViewDataDictionary is of type [duplicate]

This question already has answers here:
The model item passed into the dictionary is of type .. but this dictionary requires a model item of type
(7 answers)
Closed 4 years ago.
I am having a trouble fixing this error, I am trying to edit an information of a specific user but when I click the "Edit" button I am getting this error in my web browser saying:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'SanMarinoClassicWebsite.Auth.ApplicationUser', but this ViewDataDictionary instance requires a model item of type 'SanMarinoClassicWebsite.ViewModels.EditUserViewModel'.
what could I've done wrong?
Here is the action of my Admin Controller for editing the information
[Authorize(Roles ="Administrator")]
public class AdminController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AdminController(UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public IActionResult Index()
{
return View();
}
public IActionResult UserManagement()
{
var users = _userManager.Users;
return View(users);
}
public IActionResult AddUser()
{
return View();
}
[HttpPost]
public async Task<IActionResult> AddUser(AddUserViewModel
addUserViewModel)
{
if (!ModelState.IsValid) return View(addUserViewModel);
var user = new ApplicationUser()
{
UserName = addUserViewModel.UserName,
Email = addUserViewModel.Email,
City = addUserViewModel.City,
Birthdate = addUserViewModel.Birthdate,
Country = addUserViewModel.Country
};
IdentityResult result = await _userManager.CreateAsync(user,
addUserViewModel.Password);
if (result.Succeeded)
{
return RedirectToAction("UserManagement", _userManager.Users);
}
foreach (IdentityError error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View(addUserViewModel);
}
public async Task<IActionResult> EditUser(string id)
{
var user = await _userManager.FindByIdAsync(id);
if (user == null)
return RedirectToAction("UserManagement", _userManager.Users);
return View(user);
}
[HttpPost]
public async Task<IActionResult> EditUser(EditUserViewModel editUserViewModel)
{
var user = await _userManager.FindByIdAsync(editUserViewModel.Id);
if (user != null)
{
user.Email = editUserViewModel.Email;
user.UserName = editUserViewModel.UserName;
user.Birthdate = editUserViewModel.Birthdate;
user.City = editUserViewModel.City;
user.Country = editUserViewModel.Country;
var result = await _userManager.UpdateAsync(user);
if (result.Succeeded)
return RedirectToAction("UserManagement",
_userManager.Users);
ModelState.AddModelError("", "User not updated, something went
wrong.");
return View(editUserViewModel);
}
return RedirectToAction("UserManagement", _userManager.Users);
}
[HttpPost]
public async Task<IActionResult> DeleteUser(string userId)
{
ApplicationUser user = await _userManager.FindByIdAsync(userId);
if (user != null)
{
IdentityResult result = await _userManager.DeleteAsync(user);
if (result.Succeeded)
return RedirectToAction("UserManagement");
else
ModelState.AddModelError("", "Something went wrong while deleting this user.");
}
else
{
ModelState.AddModelError("", "This user can't be found");
}
return View("UserManagement", _userManager.Users);
}
EditUserViewModel.cs
public class EditUserViewModel
{
public string Id { get; set; }
[Required(ErrorMessage = "Please enter the user name")]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required(ErrorMessage = "Please enter the user email")]
public string Email { get; set; }
public List<string> UserClaims { get; set; }
[Required(ErrorMessage = "Please enter the birth date")]
[Display(Name = "Birth date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",
ApplyFormatInEditMode = true)]
public DateTime Birthdate { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
EditUser.cshtml
#model EditUserViewModel
<h2>Edit user</h2>
<form asp-controller="Admin" asp-action="EditUser" method="post"
class="form-horizontal" role="form">
<h4>You can change the user details below</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Id" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Id" class="form-control" />
<span asp-validation-for="Id" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="UserName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Birthdate" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Birthdate" class="form-control" />
<span asp-validation-for="Birthdate" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="City" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Country" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Country" class="form-control" />
<span asp-validation-for="Country" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-primary" value="Save user" />
<a asp-action="Index" class="btn btn-primary">Cancel</a>
</div>
</div>
</form>
You have a problem with you generic type.
Look at you controller.
public class AdminController : Controller
{
// Here is the problem
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AdminController(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
// ...
You're using ApplicationUser to create an instance of UserManager. However, are using EditUserViewModel in your view.
You should change the type of your instance _userManager or use another type in your view.
Examples:
public class AdminController : Controller
{
// Here is the problem
private readonly UserManager<EditUserViewModel> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AdminController(UserManager<EditUserViewModel> userManager, RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
// ...
Or
#model EditUserViewModel
<h2>Edit user</h2>
I hope I helped you.

MVC Url.Action causes NullReferenceException in post

I'm trying to have a button on my form page that takes me back to the previous view that requires a parameter, I'm passing a ViewModel into the view with the assigned value I'm using. If the button is un-commented the button works fine but the forms post sends a NullReferenceException, and if the button is commented the form works exactly as I want.
The button that breaks the form
<button type="button" onclick="location.href='#Url.Action("Assignments","Session", new { Model.CourseName })'">Go Back</button>
The Controller Code
public IActionResult CreateAssignment(string courseName)
{
CreateAssignmentModel assignmentModel = new CreateAssignmentModel();
assignmentModel.CourseName = courseName;
return View(assignmentModel);
}
[HttpPost]
public IActionResult CreateAssignment(CreateAssignmentModel assignment)
{
if (ModelState.IsValid)
{
ModelState.Clear();
return View(assignment.CourseName);
}
else
{
return View(assignment.CourseName);
}
}
public IActionResult Assignments(string courseName)
{
var assignments = storedProcedure.getAssignments(User.Identity.Name, courseName);
var AssignmentsView = new AssignmentsViewModel{CourseName = courseName};
foreach (var Assignment in assignments.ToList())
{
AssignmentsView.Assignments.Add(Assignment);
}
return View(AssignmentsView);
}
The Model Code
public class CreateAssignmentModel
{
public string UserName { get; set; }
public string CourseName { get; set; }
[Required]
public string AssignmentName { get; set; }
[Required]
public string AssignmentDescription { get; set; }
[Required]
public int TotalPoints { get; set; }
[Required]
public DateTime DueDate { get; set; }
}
The Form with Button
<button type="button" onclick="location.href='#Url.Action("Assignments","Session", new { Model.CourseName })'">Go Back</button>
<div class="row">
<div class="col-md-4">
<form asp-route-returnUrl="#ViewData["ReturnUrl"]" method="post">
<h4>Create an Assignment</h4>
<hr />
<div class="form-group">
<label asp-for="AssignmentName" class="control-label">Assignment Name</label>
<input asp-for="AssignmentName" class="form-control" placeholder="Assignment Name" />
<span asp-validation-for="AssignmentName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AssignmentDescription" class=" control-label">Assignment Description</label>
<input asp-for="AssignmentDescription" class="form-control" placeholder="Assignment Description" />
<span asp-validation-for="AssignmentDescription" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TotalPoints" class=" control-label">Total Points</label>
<input asp-for="TotalPoints" class="form-control" placeholder="Points" />
<span asp-validation-for="TotalPoints" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DueDate" class=" control-label">Due Date</label>
<input asp-for="DueDate" class="form-control" placeholder="Due Date" />
<span asp-validation-for="DueDate" class="text-danger"></span>
</div>
<br />
<button type="submit" class="btn btn-primary">Create</button>
</form>
</div>
</div>
Sorry for the lack of brevity, I've looked at NullReferenceException solutions for my problem but none have worked.

Resources