ModelState.IsValid() does not validate even after the previous ModelState was closed - asp.net-core

I am using an if statement which should perform some operations when the model state is valid, but apparently ModelState.IsValid does not return true. I have tried clearing the previous ModelState using ModelState.Clear() but it did not work as well.
Here is my Controller
// This is the first action for which I'm using the model state
[HttpPost]
public async Task<IActionResult> Register(userModel model)
{
if (ModelState.IsValid)
{
userData lcl_userr = new userData
{
username = model.username,
password = model.password,
email = model.email
};
_context.users.Add(lcl_userr);
await _context.SaveChangesAsync();
ViewBag.Success = "Registered successfully";
ModelState.Clear();
return View();
}
return View(model);
}
// And this is the second one
[HttpPost]
public IActionResult Index(userModel model)
{
if (ModelState.IsValid)
{
var findValue = _context.users.Any(o => o.username == model.username);
var findValue2 = _context.users.Any(o => o.password == model.password);
if (findValue && findValue2)
ViewBag.Name = "Success";
}
return View(model);
}
And here's the form
<form method="post" asp-action="Index" asp-controller="Portal">
<div class="text-danger"></div>
<div class="text-warning">#ViewBag.Name</div>
<div class="form-group">
<label class="mt-4 asp-for="username"">Username</label>
<input class="form-control" type="text" required="required" asp-for="username" />
<span></span>
</div>
<div class="form-group">
<label class="mt-4" asp-for="password">Password</label>
<input type="password" class="form-control" required="required" asp-for="password"/>
<span></span>
</div>
<center>Don't have an account? <a asp-controller="Portal" asp-action="Register">Register here</a>.</center>
<center><button value="login" class="btn btn-primary mt-3 w-25 mb-3 align-content-center">Login</button></center>
</form>
The model class being called inside the action and the class members work fine and the values it gets from the form are also working fine, it's just the model state which does not work.
The userModel class
public class userModel
{
[Display(Name = "username")]
[Required]
public string username { get; set; }
[Required]
[Display(Name = "password")]
public string password { get; set; }
[Required]
[Display(Name = "email")]
public string email { get; set; }
}

The second request to public IActionResult Index(userModel model) whose model doesn't contais email. IsValid is false.
[Required]
[Display(Name = "email")]
public string email { get; set; }
The ModelState instance for the email address has an error in the Errors collection.
When MVC creates the model state for the submitted properties, it also goes through each property in the ViewModel and validates the property using attributes associated to it. If any errors are found, they are added to the Errors collection in the property's ModelState.
Solution
Just reomve if (ModelState.IsValid) in Index action and there is no need to add it at all.
or if you insist to keep if (ModelState.IsValid), you need to add email inside form.
<input type="hidden" asp-for="email" />

Related

Pass email to ResendEmailConfirmation model/view - Identity

I'm trying to pass the user's email to Identity's ResendEmailConfirmation.cshtml class from the register page, so that it is displayed on view in the Email Input box.
Register Page - The link to redirect the user to the Resend Email Confirmation page
<a asp-area="Identity" asp-page="/Account/resendemailconfirmation" asp-route-email="#Model.Input.Email" class="resend-confirm-email-submit">Resend confirmation email</a>
ResendEmailConfirmation.cshtml - Relevant Parts
public ResendEmailConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
public void OnGet(string email)
{
// My attempt
InputModel inputModel = new InputModel();
inputModel.Email = email;
}
ResendEmailConfirmation View - Email Input Box
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email" class="register-heading-style"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
#*<button type="submit" class="btn btn-primary">Resend</button>*#
<button type="submit" class="register-submit"><span>Resend</span></button>
</form>
Thank you
You should use this way to define Input in OnGet():
Register.cshtml.cs to get the email (You didn't show this part of code, so I directly define the value):
public void OnGet()
{
Input =new InputModel()
{
Email = "asd#asd.com"
};
}
Then ResendEmailConfirmation.cshtml.cs to show the email that passed from register page:
public void OnGet(string email)
{
Input = new InputModel() //you get value from Input.Eamil in view, so you should define Input, not inputmodel
{
Email = email
};
}
You do not have to change the razor view pages.
Result:

how use two modeles in one method?

the ModelState is Invalid.I Think I pass Model Wrongly.Any Idea?
controller:
[Authorize]
[HttpPost]
public async Task<IActionResult> SendComment([Bind("CommentID,Comment,Date,AdminId")]AdminReport adminReport,int ReportID)
{
var x = _userReport.UserReports.Find(ReportID);
x.IsViewed = true;
adminReport.UserId = x.UserId;
adminReport.AdminId = _userManager.GetUserId(HttpContext.User);
if (ModelState.IsValid){
_adminReport.Add(adminReport);
await _adminReport.SaveChangesAsync();
return View(); }
return RedirectToAction("SendDoneAdmin");
}
its how I pass a Model:
<div class="card-footer">
<form asp-controller="Admin" asp-action="ُSendComment" method="post">
<input type="hidden" value="#report.ReportID" name="ReportID" />
<button type="submit" class="btn btn-primary">SendComment</button>
</form>
Model:
[Key]
public int CommentID { get; set; }
[Required]
public string Comment { get; set; }
public string AdminId { get; set; }
public string UserId { get; set; }
}`
Your quotation no clear but must know for pass data via Form tag
must all input inside Form tag
Controller
public async Task<IActionResult> SendComment()
{
// write your code....
return View(new AdminReport()); // must return new object
}
POST
Normal write again your action SendComment no any change
HTML
for pass AdminReport model must write flied inside form tag
<form asp-controller="Admin" asp-action="Viewed" method="post">
<input type="hidden" value="#report.ReportID" name="ReportID" />
/* for example */
<input type="hidden" asp-for="model.Comment" />
<button type="submit" class="btn btn-primary">SendComment</button>
</form>
No Problem if you have another view but must return View(new AdminReport());
If you want remove validation for comment prop use below code.
// remove all key
foreach (var key in ModelState.Keys).ToList())
ModelState.Remove(key);
// or for one
ModelState.Remove("comment ");
You put this [Requiried] attribute on the Comment:
[Required]
public string Comment { get; set; }
You will have to include that input in your form in order for the validation to pass.
You can add that field like this:
<div class="card-footer">
<form asp-controller="Admin" asp-action="Viewed" method="post">
<input type="hidden" value="#report.ReportID" name="ReportID" />
<input type="text" name="Comment" />
<button type="submit" class="btn btn-primary">SendComment</button>
</form>

Model not being passed to controller

One of my asp.net core pages isn't passing its model back to the controller. I've investigated similar threads in stackoverflow but none could solve my issue - what's different in this particular case?
In the attached MVC, I fill the input box "Enter here some text", then I click on button "CLICK HERE". The debugger enters correctly the controller but the variable "TEST" returns null.
Any geniuses out there able to help me out?
My Model:
namespace MyProgram.Models._04_ModuleTasker
{
public class TaskerViewModel
{
public SelectList SelectListLocations;
public SelectList SelectListUsers;
public SelectList SelectListFilters;
public string SelectedCompanyLocationDesc;
public string SelectedUserId;
public string SelectedFilter;
}
}
My View:
#model MyProgram.Models._04_ModuleTasker.TaskerViewModel
#{
ViewData["Title"] = "AllTasks";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container-fluid">
<div class="PageTitle">
Tasker
<hr class="TitleHR" />
</div>
<div style="text-align:center;margin-top:20px" class="text-body">
<form asp-controller="Tasker" asp-action="ShowActiveTasksPOST" method="post" role="form">
<input type="text" asp-for="SelectedUserId" /> Enter here some text <br />
<input type="submit" class="btn btn-success InputShortWidth LoginButton" value="CLICK HERE" />
</form>
</div>
</div>
My Controller:
[HttpPost]
public async Task<IActionResult> ShowActiveTasksPOST(TaskerViewModel taskerViewModel)
{
string TEST = taskerViewModel.SelectedUserId;
return RedirectToAction("Index", "Home");
}
To make the binding works, you need to convert the fields to properties with with setters and getters. E.g.:
public string SelectedCompanyLocationDesc { get; set; }
public string SelectedUserId { get; set; }
public string SelectedFilter { get; set; }

Validations with ViewModel - MVC4

I am trying to implement both Create and List actions in a single View. I was being suggested to use ViewModel. I am getting the object reference error. Also some good example on how to achieve this will help.
My Model Class
public class Employee
{
public int ID { get; set; }
[Required(ErrorMessage="Please enter name")]
public string Name { get; set; }
}
My View Model Class
public class EmployeeVM
{
public Employee Employee { get; set; }
public List<Employee> Employees { get; set; }
}
My Controller
[HttpPost]
public ActionResult Create(EmployeeVM emp, string Name)
{
if (ModelState.IsValid) //my modelstate is valid even when the value is empty string; it then gives an Object reference not set error
{
emp.Employee.Name = Name;
repository.SaveRole(emp);
return RedirectToAction("Index");
}
else
{
return View(emp);
}
}
My View
#model ERP.Domain.Entity.EmployeeVM
<body>
<div class="jumbotron">
#using (Html.BeginForm("Create", "MyController", FormMethod.Post))
{
#Html.ValidationSummary(true)
<label>
Name</label>
<input id="txtName" type="text" name="Name" class="btn btn-default" />
#Html.ValidationMessageFor(model => model.Employee.Name)
<input type="submit" value="Save" class="btn btn-primary" />
}
</div>
Also I was suggested in StackOverflow to go with ViewModel approach if I want to use both Create and List in the same View? Is it the right approach. Some example may help.

.NET MVC 4 Strongly typed ViewModel containing Strongly typed Model with EditorFor and EditorTemplate partial view not binding

There has been a lot of questions about this... but somehow I can't get this binding to work and I'm still getting null values in my posted View Model. This is MVC 4.
Here is the Main View Model
public class RoleVM {
[Required]
[Display(Name = "Name of the Role")]
public string Role {get; set;}
public IEnumerable<RolePermission> permissions { get; set; }
}
Here is the RolePermission Class
public class RolePermission {
public int id;
public bool permission_value;
public string name { get; set; }
}
Here is GET Create Method in the controller
public ActionResult Create() {
RoleVM role_vm = new RoleVM();
var allpermissions = from p
in permission_repo.GetPermissions()
select p;
role_vm.permissions = from p
in allpermissions
select new RolePermission
{ name = p.name, id = p.PermissionId, permission_value = false };
return View(role_vm);
}
Here is the Create.cshtml file
#model RoleVM
#using (Html.BeginForm("Create", "Role",
FormMethod.Post, new { #class = "permission_form" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>RoleVM</legend>
<div class="form-item">
#Html.LabelFor(model => model.Role)
#Html.EditorFor(model => model.Role)
#Html.ValidationMessageFor(model => model.Role)
</div>
#Html.EditorFor(model => model.permissions)
<p>
<input class="submit-btn" type="submit" value="Create" />
</p>
</fieldset>
}
Next here is the rolepermissions.cshtml file located in ~/Views/Shared/EditorTemplates
#model RolePermission
<div class="form-item">
#Html.HiddenFor(modelItem => modelItem.id)
#Html.LabelFor(modelItem => modelItem.permission_value, Model.name)
#Html.CheckBoxFor(modelItem => modelItem.permission_value)
</div>
Here is an example of one of the html items that is rendered on page
<div class="form-item">
<input data-val="true" data-val-number="The field Int32 must be a number." data-val-required="The Int32 field is required." id="permissions_2__id" name="permissions[2].id" type="hidden" value="3" />
<label for="permissions_2__permission_value">Role-Edit</label>
<input data-val="true" data-val-required="The Boolean field is required." id="permissions_2__permission_value" name="permissions[2].permission_value"
type="checkbox" value="true" /><input name="permissions[2].permission_value" type="hidden" value="false" />
</div>
Finally here is the Create POST method
[HttpPost]
public ActionResult Create(RoleVM rolevm)
{
//In here rolevm.role is populated based on the textbox input
//However rolevm.permissions is there with the correct
//number of items, but the values all are not binded
// id is null, name is empty, and permission_value is false
// regardless of which checkboxes were checked
return RedirectToAction("Index");
}
Any help on the binding issue with the posted model would be really great.
This was a simple issue, if someone else comes across it maybe this will help them. I didn't have the properties on the class declared as properties with get; set;
public class RolePermission {
public int id { get; set; }
public bool permission_value { get; set; }
public string name { get; set; }
}