ModelState.AddModelError not displaying error in view - ASP.NET - asp.net

I have been banging my head against the wall trying to solve this issue.
I have this view controller
public class LoginController : Controller
{
public ActionResult Index(LoginClass model)
{
return View(model);
}
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (!this.ModelState.IsValid)
{
return this.View(model);
}
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect");
}
}
return RedirectToAction("Index", "Login", model);
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
}
and here is my view:
<section id="login">
<div class="container">
<form action="~/Login/Login" id="Login" method="post">
<div class="row">
<div class="col-md-12">
<p>
<label for="username">Username</label>
<input type="text" id="username" name="username" class="form-control" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<input type="submit" id="submit" name="submit" value="Login" class="btn btn-default" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<label for="password">Remember Me?</label>
<input type="checkbox" id="chkPersist" name="chkPersist" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
#Html.ValidationSummary()
</p>
</div>
</div>
</form>
</div>
</section>
My issue is that my error message is not appearing when I enter the wrong username and password. Why is not displaying?

The problem is with the last line in your Login method. You are calling RedirectToAction instead of View. This has the consequence that you lose all your view specific state including the model state and validation errors that you built up in your Login Action. You can change your Login method like so (I simplified it a little), really the only change is replacing RedirectToAction("Index", "Login", model) with View(model) on the last line.
If you do want to redirect in the event of authentication failure and you did want to use RedirectToAction then see my other answer I posted here.
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (!this.ModelState.IsValid)
return this.View(model);
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect");
return this.View(model); // return to the same view to show your error message
// return RedirectToAction("Index", "Login", model); // do not redirect
}

You need to add a placeholder by using the Html Helper function to display the message.
<div>#Html.ValidationMesssage("KeyName")</div>
to your view so that you can display the validation message.
The KeyName comes from controller
ModelState.AddModelError("KeyName", "The user name or password provided is incorrect");
Also you may need to ensure client side validation is enabled in your web.config.(usually they are)
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

Related

Why is my validation code for .net core 3. not working as intended?

I am trying to make a validation for my report form where the report can only be submited if the email = to "Sample#email.com". My problem is the code works perfectly without the validation but when I include the validation code if (!ModelState.IsValid){return View("Create");} into the my controller the validation works perfectly but when the email is correct it just refreshes the page without submiting it or redirecting it to the submit view
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Submit(Reports report)
{
if (!ModelState.IsValid)
{
return View("Create");
}
_reportRepository.CreateReport(report);
return View();
Validation Code:
public class EmailValidation : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var report = (Reports)validationContext.ObjectInstance;
if (report.Email == "Sample#email.com")
{
return ValidationResult.Success;
}
return new ValidationResult("Invalid email");
}
}
Report:
public class Reports
{
[Key]
public int ReportId { get; set; }
[Required(ErrorMessage = "Please enter email.")]
[Display(Name = "Email :")]
[EmailValidation(ErrorMessage ="enter valid email")]
public string Email { get; set; }
}
Create View:
#model Reports
#using Microsoft.AspNetCore.Identity
#inject UserManager<IdentityUser> UserManager
<body>
<form asp-action="Submit" method="post" role="form">
<div class="container1">
<div class=" form-group row">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-3">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group row float-right">
<div class="col-md-offset-2 col-md-5 float-md-left">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>

Process ModelState errors from WebAPI Blazor (server-side) call

When I am making a WebAPI call I want to find out how to pass back ModelState errors to my Blazor application.
The DataAnnotations all validate correctly but, if I do any other types of validation (once past the ModelState.IsValid call), I can't get those errors that I add to the ModelState to pass back to Blazor. What am I missing?
Blazor page
...
<EditForm Model="#_user" OnValidSubmit="#Update">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="container">
<div class="row">
<div class="col-md-3">Name:</div>
<div class="col-md-9"><InputText id="Name" #bind-Value="#_user.UserName" class="form-control" /></div>
</div>
#if (_user.isNew)
{
<div class="row">
<div class="col-md-3">Password:</div>
<div class="col-md-9"><InputText id="Name" #bind-Value="#_user.Password" class="form-control" type="password" /></div>
</div>
<div class="row">
<div class="col-md-3">Validate your password:</div>
<div class="col-md-9"><InputText id="Name" #bind-Value="#_user.ValidatePassword" class="form-control" type="password" /></div>
</div>
}
<div class="row">
<div class="col-md-3">Email:</div>
<div class="col-md-9"><InputText id="Name" #bind-Value="#_user.Email" class="form-control" /></div>
</div>
<div class="row">
<div class="col-md-3">Roles:</div>
<div class="col-md-9">
#foreach (IdentityRole role in _roles)
{
bool isChecked = _user.UserRoles.Any(r => r.Id == role.Id);
<input type="checkbox" Id="#role.Id" name="#role.Id"
Class="form-control" checked="#isChecked" #onchange="#(e => RoleChecked(e, role.Id))" />
#role.Name
}
</div>
</div>
<button type="submit" class="btn btn-#buttonClass">#buttonText</button>
</div>
</EditForm>
}
#functions {
[Parameter]
string id { get; set; } = "";
private UserViewModel _user { get; set; }
...
private async Task Update()
{
if (id != "")
{
await apiClient.UpdateUserAsync(_user);
}
else
{
await apiClient.AddUserAsync(_user);
}
UriHelper.NavigateTo("admin/users");
}
...
WebAPI Controller
[HttpPost]
public async Task<IActionResult> Post([FromBody] UserViewModel applicationUser)
{
if (applicationUser == null)
{
_logger.LogError($"ApplicationUser object null");
return BadRequest("ApplicationUser object is null");
}
if (!ModelState.IsValid)
{
_logger.LogWarn("ApplicationUser object invalid");
return BadRequest(ModelState);
}
else
{
_logger.LogDebug($"Creating ApplicationUser {applicationUser.UserName}");
var obj = new ApplicationUser();
obj.Map(applicationUser);
IdentityResult result = await _userManager.CreateAsync(obj, applicationUser.Password);
if (result.Succeeded)
{
//put the newly created user back on top of the parameter for role creation
applicationUser.Map(obj);
await IdentityHelpers.UpdateUserRoles(_userManager, applicationUser);
return CreatedAtRoute("", new { id = applicationUser.Id }, applicationUser);
}
else
{
_logger.LogWarn("ApplicationUser object could not be created");
result.Errors.ToList().ForEach(e => ModelState.AddModelError(e.Code, e.Description));
return BadRequest(ModelState);
}
}
}
How do I pass back ModelState errors to Blazor so that it will respond to those in the same way that it would DataAnnotations (or model validation)?

How to send a submitted email to an email

I am currently using a template in order to create a website. In the contact page I want to create a form where the user will be able to contact the company from a contact us template. The template comes with a contact_us.php file but I want to use only asp.net for the emails.
I am a beginner and I am not really sure how the controllers works in asp.net.
Heres my code:
View: Contact.cshtml
#model Gsite.Models.ContactUs
#{
Layout = "~/Views/Shared/_CustomLayout.cshtml";
}
<script src="~/Content/vendor/jquery/jquery.js"></script>
<script src="~/Content/vendor/jquery/jquery.min.js"></script>
<!-- Contact Form -->
<!-- In order to set the email address and subject line for the contact form go to the bin/contact_me.php file. -->
<div class="row">
<div class="col-lg-8 mb-4">
<h3>Send us a Message</h3>
#if (ViewBag.Message == null)
{
<form method ="post" name="sentMessage" id="contactForm" novalidate>
<div class="control-group form-group">
<div class="controls">
<label asp-for="Name">Full Name:</label>
<input asp-for="Name" type="text" class="form-control" id="name" required data-validation-required-message="Please enter your name.">
<span asp-validation-for="Name"
class="text-muted"></span>
<p class="help-block"></p>
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label asp-for="phonenumber">Phone Number:</label>
<input asp-for="phonenumber" type="tel" class="form-control" id="phone" required data-validation-required-message="Please enter your phone number.">
<span asp-validation-for="phonenumber"
class="text-muted"></span>
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label asp-for="Email">Email Address:</label>
<input asp-for="Email" type="email" class="form-control" id="email" required data-validation-required-message="Please enter your email address.">
<span asp-validation-for="Email"
class="text-muted"></span>
</div>
</div>
<div class="control-group form-group">
<div class="controls">
<label asp-for="Message">Message:</label>
<textarea asp-for="Message" rows="10" cols="100" class="form-control" id="message" required data-validation-required-message="Please enter your message" maxlength="999" style="resize:none"></textarea>
<span asp-validation-for="Message"
class="text-muted"></span>
</div>
</div>
<div id="success"></div>
<!-- For success/fail messages -->
<button type="submit" class="btn btn-primary" id="sendMessageButton">Send Message</button>
</form>
}
</div>
</div>
<!-- /.row -->
<div>
<div>
#if (ViewBag.Message != null)
{
<div>#ViewBag.Message</div>
}
</div>
</div>
</div>
<script src="~/Content/vendor/jquery/jquery.min.js"></script>
<script src="~/Scripts/jqBootstrapValidation.js"></script>
<script src="~/Scripts/contact_me.js"></script>
Controller: ContactController
namespace Gsite.Controllers
{
public class ContactController : Controller
{
// GET: Contact
public ActionResult Contact()
{
return View();
}
[HttpPost]
public ActionResult Contact(ContactUs vm)
{
if (ModelState.IsValid)
{
try
{
MailMessage msz = new MailMessage();
msz.From = new MailAddress(vm.Email);//Email which you are getting
//from contact us page
msz.To.Add("xxx#xxx.com");//Where mail will be sent
msz.Body = vm.Message;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.Credentials = new System.Net.NetworkCredential
("xxxxx#xxxxx.com", "xxxxx");
smtp.EnableSsl = true;
smtp.Send(msz);
ModelState.Clear();
ViewBag.Message = "Thank you for Contacting us ";
}
catch (Exception ex)
{
ModelState.Clear();
ViewBag.Message = $" Sorry we are facing Problem here {ex.Message}";
}
}
return View();
}
public ActionResult Error()
{
return View();
}
}
}
Model: ContactUs.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace Gsite.Models
{
public class ContactUs
{
[Required]
[StringLength(20, MinimumLength = 5)]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
public string Message { get; set; }
[Required]
public int phonenumber { get; set; }
}
}
This will work in an Asp.net MVC application. Does the application has got both Asp.net MVC and Php codes? Assuming 'yes', you need to set the action property of the form element.
e.g. <form action="/Contact/Contact">
Also set the "name" property of the input boxes to match the properties of the ContactUs object.

Request method 'POST' not supported - SPRING

login.jsp
<div id="login" class="animate form">
<form action="${loginUrl}" method="POST">
<h1>Log in</h1>
<c:url var="loginUrl" value="/login" />
<c:if test="${param.error != null}">
<input type="text" class="alert-danger" id="danger" name="danger"
placeholder="Invalid username and password." disabled />
<br />
</c:if>
<c:if test="${param.logout != null}">
<input type="text" class="alert-success" id="success"
name="success"
placeholder="You have been logged out successfully." disabled />
<br />
</c:if>
<p>
<label for="username" class="uname" data-icon="u"> Your
email </label> <input id="username" name="login" required="required"
type="text" placeholder="mymail#atos.net" />
</p>
<p>
<label for="password" class="youpasswd" data-icon="p">
Your password </label> <input id="password" name="password"
required="required" type="password" placeholder="eg. X8df!90EO" />
</p>
<p class="keeplogin">
<input type="checkbox" name="remember-me" id="rememberme"
value="rememberme" /> <label for="rememberme">Remember
Me</label>
</p>
<p class="login button">
<input type="submit" value="Login" />
</p>
<p class="change_link"></p>
</form>
</div>
userlist.jsp
<div class="generic-container">
<%#include file="authheader.jsp" %>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading"><span class="lead">List of Users </span></div>
<table class="table table-hover">
<thead>
<tr>
<th>Prenom</th>
<th>Nom</th>
<th>Matricule</th>
<th>Login</th>
<sec:authorize access="hasRole('ADMIN') or hasRole('READ')">
<th width="100"></th>
</sec:authorize>
<sec:authorize access="hasRole('ADMIN')">
<th width="100"></th>
</sec:authorize>
</tr>
</thead>
<tbody>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.prenom}</td>
<td>${user.nom}</td>
<td>${user.matricule}</td>
<td>${user.login}</td>
<sec:authorize access="hasRole('ADMIN') or hasRole('READ')">
<td>edit</td>
</sec:authorize>
<sec:authorize access="hasRole('ADMIN')">
<td>delete</td>
</sec:authorize>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<sec:authorize access="hasRole('ADMIN')">
<div class="well">
Add New User
</div>
</sec:authorize>
</div>
AppController.java
#Controller
#RequestMapping("/")
#SessionAttributes("roles")
public class AppController {
#Autowired
IService_User<USER> userService;
#Autowired
IService<COMPTE> compteService;
#Autowired
MessageSource messageSource;
#Autowired
PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices;
#Autowired
AuthenticationTrustResolver authenticationTrustResolver;
#RequestMapping(value = { "/", "/list" }, method = { RequestMethod.GET, RequestMethod.POST })
public String listUsers(ModelMap model) {
List<USER> users = userService.findAllOBJECTS();
model.addAttribute("users", users);
model.addAttribute("loggedinuser", getPrincipal());
return "userslist";
}
#RequestMapping(value = {"/login"}, method = { RequestMethod.GET, RequestMethod.POST })
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
}
There are 2 pages: login.jsp - start page which includes form to be populated with login and password - userlist.jsp list of results "display all users persisted in DB"..
First the login page is shown, when i click on submit button i got this error:
org.springframework.web.servlet.PageNotFound - Request method 'POST' not supported
In your login.jsp you are using http method POST
<form action="${loginUrl}" method="POST">
and in controller, you are using http method GET
#RequestMapping(value = {"/login"}, method = RequestMethod.GET)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
Problem will be solved after changing method = RequestMethod.POST in your controller like this
#RequestMapping(value = {"/login"}, method = RequestMethod.POST)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
In your login form you are explicitly making an POST request... and in your controller the the url is mapped to GET request.. this is the issue... Please make the controller as POST... like
#RequestMapping(value = {"/login"}, method = RequestMethod.POST)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
Add post method in #RequestMapping annotation, like following;)
#RequestMapping(value = {"/login"}, method = {RequestMethod.GET, RequestMethod.POST})
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
if you are using spring security 4.x.x. , CSRF is enabled by default. therefore you have to provide the csrf filed in your form.
Adding the csrf token as hidden fields does the trick:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

MVC4 Posting a form not calling Controller method

I have the following form in my View.
#using (Html.BeginForm("PostComment", "Blog")) name)
{
<fieldset id="frmTester">
<div class="formContainer">
<span><input id="username" name="username" /></span>
<input id="submit" name="submit" type="submit" value="Submit" />
</div>
</fieldset>
}
Now I have the following Method in my BlogController...
public ActionResult PostComment(string username)
{
return View();
}
I really don't get MVC very well. I dont see why I cant get the above ActionResult method to execute. I'm just trying to handle a postback. Anyone have any idea why this doesn't work or an alternative approach.
use [HttpPost] :
[HttpPost]
public ActionResult PostComment(string username)
{
string u = Request.Form["username"] ;
// return Content(u); //if you want dispaly username use this
return View();
}
Change your view code to this...
#using (Html.BeginForm("PostComment", "Blog", FormMethod.Post))
{
<fieldset id="frmTester">
<div class="formContainer">
<span><input id="username" name="username" type="text" /></span>
<input id="submit" name="submit" type="submit" value="Submit" />
</div>
</fieldset>
}
and your action method to....
[HttpPost]
public ActionResult PostComment(string username)
{
return View();
}

Resources