Validation Error not being displayed (MVC4 and EF) - asp.net-mvc

The invalid login error message is not being displayed for incorrect username or password. I have a Model called User and a Controller with the Action Method Validate, which validates the username and password. Upon successful validation I redirect to Create Action method, if not I add a model error and I want to display an "Invalid username or password" message on the login screen.
Model:
public class User
{
public int ID { get; set; }
[Required]
[Display(Name="User Name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[Display(Name="First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name="Last Name")]
public string LastName { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[MinLength(10)]
[MaxLength(10)]
[Display(Name="Mobile No")]
public string PhoneNum { get; set; }
}
Controller:
[HttpGet]
public ActionResult Validate()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Validate(User user)
{
var u1 = db.Users.Where(p => p.UserName == user.UserName && p.Password == user.Password).FirstOrDefault();
if (u1 != null)
{
return RedirectToAction("Create");
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
return RedirectToAction("Validate");
}
View:
#model HindiMovie.Models.User
#{ViewBag.Title = "Login";}
<h2>Login</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(false,"The user name or password provided is incorrect.")
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<p>
<input type="submit" value="Validate" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}

Redirecting resets the ModelState. You probably want to re-display the view instead:
public ActionResult Validate(User user)
{
var u1 = db.Users.Where(p => p.UserName == user.UserName && p.Password == user.Password).FirstOrDefault();
if (u1 != null)
{
return RedirectToAction("Create");
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View();
}

Related

Umbraco 7.6.2: Cannot bind source type <my model> to model type Umbraco.Core.Models.IPublishedContent

I am trying to create a custom login form with Umbraco 7.6.2 I created a partial view for the form, a model and a surface controller based on Umbraco.Web.Mvc.SurfaceController.
After all that I get the error:
Cannot bind source type 'name of my model' to model type Umbraco.Core.Models.IPublishedContent.
Controller:
public class UserSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
//
// GET: /User/
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(Models.UserModel user)
{
if (ModelState.IsValid)
{
if (user.IsValid(user.UserName, user.Password))
{
FormsAuthentication.SetAuthCookie(user.UserName, user.RememberMe);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "Login data is incorrect!");
}
}
return View(user);
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
}
Model:
public class UserModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember on this computer")]
public bool RememberMe { get; set; }
/// <summary>
/// Checks if user with given password exists in the database
/// </summary>
/// <param name="_username">User name</param>
/// <param name="_password">User password</param>
/// <returns>True if user exist and password is correct</returns>
public bool IsValid(string _username, string _password)
{
if (_username == "username" && _password == "password")
{
return true;
}
else
{
return false;
}
}
}
View:
#inherits Umbraco.Web.Mvc.UmbracoViewPage<IPublishedContent>
#{
Layout = "Master.cshtml";
}
#Html.Partial("User", new namespace.UserModel());
Partial view:
#model namespace.UserModel
<div role="content">
<div class="container">
<div class="row">
<div class="col">
#using (Html.BeginUmbracoForm<namespace.Controllers.UserSurfaceController>("Login", "UserSurface"))
{
<div>
<fieldset>
<legend>Login</legend>
<div class="editor-label">
#Html.LabelFor(u => u.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(u => u.UserName)
#Html.ValidationMessageFor(u => u.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(u => u.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(u => u.Password)
#Html.ValidationMessageFor(u => u.Password)
</div>
<div class="editor-label">
#Html.CheckBoxFor(u => u.RememberMe)
#Html.LabelFor(u => u.RememberMe)
</div>
<input type="submit" value="Log In" />
</fieldset>
</div>
}
</div>
</div>
</div>
</div>
What may I be doing wrong here? Considering this is Umbraco 7.6.2.
In your View, you are expecting IPublishedContent.
#inherits Umbraco.Web.Mvc.UmbracoViewPage<IPublishedContent>
You didn't provide code of that model. Double check if this model is inheriting RenderModel. Your UserModel for partial is fine.

Button repeatedly calls GET method and does not POST when editing

I am trying to edit an entry in my database, but when I click submit, it just keeps calling the GET method over and over again and I cannot figure out why. I have tested this through breakpoints and there is no evidence of the POST method running - is it something to do with my Manufacturer binding?
Controller
// GET: Model/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Model model = db.Models.Find(id);
if (model == null)
{
return HttpNotFound();
}
ViewBag.Manufacturers = GetManufacturerList(model);
return View(model);
}
// POST: Model/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var modelToUpdate = db.Models.Find(id);
if (TryUpdateModel(modelToUpdate, "",
new string[] { "ModelName", "ManufacturerID" }))
{
try
{
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
ViewBag.Manufacturers = GetManufacturerList();
return View(modelToUpdate);
}
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Model</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ModelID)
<div class="form-group">
#Html.LabelFor(model => model.ModelName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ModelName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ModelName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Manufacturer.ManufacturerName, "Manufacturer",
htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.DropDownList("ManufacturerID", (List<SelectListItem>)ViewBag.Manufacturers,
htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Manufacturer.ManufacturerName, "",
new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
Models:
public class Model
{
[Required]
[Display(Name = "Manufacturer")]
[ForeignKey("Manufacturer")]
public int ManufacturerID { get; set; }
[Required]
public int ModelID { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Model cannot be longer than 50 characters.")]
[RegularExpression(#"^[a-zA-Z0-9.-/() ]+$", ErrorMessage = "Invalid characters used. A-Z or a-z, 0-9, '.', '-', '()' and '/' allowed.")]
[Display(Name = "Model")]
public string ModelName { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
public class Manufacturer
{
[Required]
public int ManufacturerID { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Manufacturer cannot be longer than 50 characters.")]
[RegularExpression(#"^[a-zA-Z0-9.-/() ]+$", ErrorMessage = "Invalid characters used. A-Z or a-z, 0-9, '.', '-', '()' and '/' allowed.")]
[Display(Name = "Manufacturer")]
public string ManufacturerName { get; set; }
public virtual ICollection<Model> Models { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
Thanks in advance. Any help is greatly appreciated.
Your HttpPost method is named "EditPost". Shouldn't it be named simply "Edit" like this?
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Model model)
{
Here is a tutorial that might help you: https://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/examining-the-edit-methods-and-edit-view
Figured it out - I forgot to add the ActionName attribute as below:
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{...}

MVC Model not posting

When I click the login button I never get my model posted to the server. However if I accept a FormCollection I will see the values. How can I make this automatically bind to my model instead of searching the Form Collection?
From what I have read there are a few common problems for this:
1 - your view does not specify what model you are using (#model myApp.Models.name)
2 - Your model does not use properties
3 - Any of the required fields are missing
Controller
[HttpGet]
public ActionResult Password()
{
return View(new AuthViewModel());
}
[HttpPost]
public ActionResult Password(AuthViewModel password)
{
if (password == null || string.IsNullOrEmpty(password.Password))
{
ViewBag.Error = Constants.ErrorMessages.UserPassword_PassBlank;
return View(new AuthViewModel());
}
//success
return Redirect("/");
}
Model
public class AuthViewModel
{
public string Password { get; set; }
}
View
#model MvcApplication1.Models.AuthViewModel
#{
ViewBag.Title = "Password";
}
<h2>Password</h2>
#using (Html.BeginForm())
{
<div>#Html.TextBoxFor(m => m.Password,new{placeholder="Password",type="password",autofocus=""})</div>
<div><button id="btnLogin" type="submit">Login</button></div>
<div class="error">#ViewBag.Error</div>
}
Not sure why Dan's answer isn't working without trying it, looks like it should.
I took a look at some of my code for a login form, similar to yours.
Here's mine :
public class SignInModel
{
[Required]
[Display(Name = "Enter your email address")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Enter your password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
The main difference I see is that mine has the [DataType(DataType.Password)] attribute on the password. Not sure if this makes that much difference though.
The other thing I noticed is different is that in my form I specify that the form method is POST. Also I've used the EditorFor() helper instead of textbox or password:
#using (Html.BeginForm("SignIn", "Account", "POST"))
{
<div class="form-field">
#Html.LabelFor(x => x.Email)
#Html.EditorFor(m => m.Email)
</div>
<div class="form-field">
#Html.LabelFor(x => x.Password)
#Html.EditorFor(m => m.Password)
</div>
<div class="form-remember">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(x => x.RememberMe)
</div>
<button type="submit">
Sign In</button>
}
use the following
#using (Html.BeginForm())
{
<div>#Html.PasswordFor(model => model.Password)</div>
<div><input id="btnLogin" type="submit" value="Login"/></div>
<div class="error">#ViewBag.Error</div>
}

Validation not working in partial view

I have an Index page which has two partial views: login and register.I am using data model validation.
Login.cshtml
#model Project.ViewModel.UserModel
<div style="position:inherit;">
#using (Html.BeginForm("_Login", "account"))
{
#Html.ValidationSummary(true)
<div class="label">#Html.Label("Username")</div>
<div class="field">#Html.TextBoxFor(m => m.Username)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Username)</div>
<div class="label">#Html.Label("Password")</div>
<div class="field">#Html.PasswordFor(m => m.Password)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Password)</div>
<input class="field" id="submit" type="submit" value="Login" />
}
Register.cshtml
#model Project.ViewModel.UserModel
<link href="~/Content/Site.css" rel="stylesheet" />
<div style="position: inherit; margin-top: 20px">
#using (Html.BeginForm("_Register","account"))
{
<div class="label">#Html.Label("Name")</div>
<div class="field">#Html.TextBoxFor(m => m.FullName)</div>
<div class="error">#Html.ValidationMessageFor(model => model.FullName)</div>
<div class="label">#Html.Label("Username")</div>
<div class="field">#Html.TextBoxFor(m => m.Username)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Username)</div>
<div class="label">#Html.Label("Password")</div>
<div class="field">#Html.PasswordFor(m => m.Password)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Password)</div>
<div class="label">#Html.Label("Confirm Password")</div>
<div class="field">#Html.PasswordFor(m => m.ConfirmPassword)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Password)</div>
<div class="label">#Html.Label("Email")</div>
<div class="field">#Html.TextBoxFor(m => m.Email)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Email)</div>
<div class="label">#Html.Label("Country")</div>
<div class="field">#Html.TextBoxFor(m => m.Country)</div>
<div class="error">#Html.ValidationMessageFor(model => model.Email)</div>
<input class="field" id="submit" type="submit" value="Sign Up" />
#Html.ValidationSummary()
}
Index.cshtml
#model Project.ViewModel.UserModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="regiserandlogin">
<div id="registerandlogin-header">
<label style="margin-left:50px;">Sign Up For Free!!!</label>
<label style="margin-left:350px;color:#28a1e2">Already Have An Account?</label>
</div>
<div id="registerbox">
#Html.Partial("_Register", new ProjectHub.ViewModel.UserModel())
</div>
<div id="loginbox">
#Html.Partial("_Login", new ProjectHub.ViewModel.UserModel())
</div>
public ViewResult _Register()
{
return View("_Register");
}
[HttpPost]
public ActionResult _Register(UserModel usermodel)
{
if (!ModelState.IsValid)
{
return View("Index");
}
try
{
FormsAuthentication.SetAuthCookie(usermodel.Username, false);
return RedirectToAction("activationemail", new {username= Username});
}
catch (Exception ae)
{
ModelState.AddModelError("", ae.Message);
return View();
}
}
public ViewResult _Login()
{
return View("_Login");
}
[HttpPost]
public ActionResult _Login(string username, string password)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(username, password))
{
if (!repository.IsVerified(username))
{
ModelState.AddModelError("","Account is not activated.;
return View();
}
FormsAuthentication.SetAuthCookie(username,false);
return RedirectToAction("Index","Home");
}
return RedirectToAction("Index", "account"); ;
}
else
{
ModelState.AddModelError("","Invalid Username/Password");
return View();
}
}
UserModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace ProjectHub.ViewModel
{
public class UserModel
{
[Required(ErrorMessage="Username is Required")]
public string Username { get; set; }
[Required(ErrorMessage = "Password is Required")]
public string Password { get; set; }
[Required(ErrorMessage = "Password is Required")]
public string ConfirmPassword { get; set; }
[Required(ErrorMessage = "Name is Required")]
public string FullName { get; set; }
[Required(ErrorMessage = "Email is Required")]
public string Email { get; set; }
[Required(ErrorMessage = "Country is Required")]
public string Country { get; set; }
}
}
When I press register button like this, I get a validation error
If I use RedirectToAction Method, I don't get the validation error.
Please advise me.
You should not use the same view model for both partials. You should have 2 different view models.
For example:
public class LoginViewModel
{
[Required(ErrorMessage="Username is Required")]
public string Username { get; set; }
[Required(ErrorMessage = "Password is Required")]
public string Password { get; set; }
}
and for the register partial:
public class RegisterViewModel
{
[Required(ErrorMessage="Username is Required")]
public string Username { get; set; }
[Required(ErrorMessage = "Password is Required")]
public string Password { get; set; }
[Required(ErrorMessage = "Password is Required")]
public string ConfirmPassword { get; set; }
[Required(ErrorMessage = "Name is Required")]
public string FullName { get; set; }
[Required(ErrorMessage = "Email is Required")]
public string Email { get; set; }
[Required(ErrorMessage = "Country is Required")]
public string Country { get; set; }
}
and then your main view model should aggregate those 2 view models:
public class MyViewModel
{
public LoginViewModel Login { get; set; }
public LoginViewModel Register { get; set; }
}
and then:
<div id="registerbox">
#Html.Partial("_Register", Model.Login)
</div>
<div id="loginbox">
#Html.Partial("_Login", Model.Register)
</div>
Add the following reference to the JQuery scripts in your View.
I went through the same situation and it solved my problem.
"~/Scripts/jquery.unobtrusive*"
"~/Scripts/jquery.validate*"

ASP.NET MVC3 Remote Validation does not output error message

I have a simple Model that is the default RegisterModel and upon creating a View based on that model for Create I end up having
public class RegisterModel
{
[Required]
[Remote("UserNameExists", "Account", "", ErrorMessage = "Username is already taken.")]
[Display(Name = "Username (spaces will be stripped, must be at least 6 characters long)")]
public string UserName { get; set; }
[Required]
[Editable(true)]
[Display(Name = "First and Last name")]
public string Name { get; set; }
[Required]
[DataType(DataType.EmailAddress, ErrorMessage = "You need to enter a valid email")]
[Remote("EmailExists", "Account", "", ErrorMessage = "Email is already taken.")]
[Display(Name = "Email address")]
public string Email { get; set; }
//[Required]
//[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Create a password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Verify password")]
//[Compare("Password", ErrorMessage = "Password's do not match.")]
public string ConfirmPassword { get; set; }
}
and in the View:
<h3>
Details</h3>
#using (Html.BeginForm("GenerateBetaLink", "Account", FormMethod.Post, new { #id = "beta-user" }))
{
#Html.ValidationSummary(true)
<div>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<p>
</p>
<p>
<input type="submit" value="Create Beta User" class="btn-submit" />
<span class="loading"></span>
</p>
</div>
}
My Validation Controller
public class ValidationController : Controller
{
public JsonResult UserNameExists(string UserName)
{
OnlineServicesRepository db = new OnlineServicesRepository();
var user = db.FindUserByUsername(UserName.Trim());
return user == null ?
Json(true, JsonRequestBehavior.AllowGet) :
Json(string.Format("{0} is not available.", UserName),
JsonRequestBehavior.AllowGet);
}
public JsonResult EmailExists(string Email)
{
OnlineServicesRepository db = new OnlineServicesRepository();
var user = db.FindUserByEmail(Email.Trim());
return user != null ?
Json(true, JsonRequestBehavior.AllowGet) :
Json(string.Format("{0} is not available.", Email),
JsonRequestBehavior.AllowGet);
}
}
My problem is that Remote Validation does fire, but does not write anything into the Error Message as it should, plus, the jQuery method .valid() keeps telling me that the form is valid:
(source: balexandre.com)
What am I missing here?
The MSDN article shows the same code (in the downloadable file)
The following worked fine for me:
Model:
public class RegisterModel
{
[Required]
[DataType(DataType.EmailAddress, ErrorMessage = "You need to enter a valid email")]
[Remote("EmailExists", "Home", "")]
[Display(Name = "Email address")]
public string Email { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(RegisterModel model)
{
return View(model);
}
public ActionResult EmailExists(string email)
{
if ((email ?? string.Empty).Contains("foo"))
{
return Json(email + " is not available", JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
}
View:
#model RegisterModel
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.LabelFor(model => model.Email)
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
<input type="submit" value="OK" />
}
I had the same problem and resolved it by updating to the latest jQuery (1.6) and jQuery.validate (1.8) libraries. The easiest way to get these is searching NuGet for jQuery.

Resources