Title says it all, can anyone spot what I'm doing wrong. I've tried moving around my HTMlValidation Summary and a bunch of other things. I feel like it may have something to with the views I am returning from my Controller Class.
-- Model
public class Login
{
[Required(ErrorMessage = "First Name is required")]
[Display(Name = "First Namex")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Password is required")]
[DataType(DataType.Password)]
[Display(Name = "Passwordx")]
public string Password { get; set; }
}
-- Controller
[HttpPost]
public ActionResult Login(string FirstName, string Password)
{
if (ModelState.IsValid)
{
bool validLogin = new UserBAL().ValidateUser(FirstName, Password);
{
if (validLogin == true)
{
return RedirectToAction("Index", "Invoice");
}
else
{
return RedirectToAction("Index");
// ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
}
return View();
}
--View
#using (Html.BeginForm("Login", "Home"))
{ #Html.ValidationSummary(true)
<div>
<fieldset>
<legend>Login</legend>
<div class ="fields">
#Html.LabelFor(u => u.FirstName)
</div>
#Html.TextBoxFor(u => u.FirstName)
#Html.ValidationMessageFor(u => u.FirstName) <br />
<div class ="fields">
#Html.LabelFor(u => u.Password)
</div>
#Html.PasswordFor(u => u.Password) <br />
<input type="submit" value="Log In" />
</fieldset>
</div>
}
[HttpPost]
public ActionResult Login(EIAS.Models.Login login)
{
if (ModelState.IsValid)
{
bool validLogin = new UserBAL().ValidateUser(login);
{
if (validLogin == true)
{
return RedirectToAction("Index", "Invoice");
}
else
{
return RedirectToAction ("Index");
// ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
}
return View();
}
MVC in if (ModelState.IsValid) validate the model, and you don't receive the model in your action:
public ActionResult Login(string FirstName, string Password)
change the parameters of the action to:
public ActionResult Login(Login model)
and, for validate in the client, check if:
if you include jquery validate plugin (js)
check your web.config, keys ClientValidationEnabled and UnobtrusiveJavaScriptEnabled ir are in true.
check this link
You have to take the Model as the parameter to your Login action
public ActionResult Login()
{
// This will return the view with the form that you have above
return View();
}
[HttpPost]
public ActionResult Login(Login login)
{
// this is what your form will post too
if (ModelState.IsValid)
{
bool validLogin = new UserBAL().ValidateUser(login.FirstName, login.Password);
{
if (validLogin == true)
{
return RedirectToAction("Index", "Invoice");
}
else
{
return RedirectToAction("Index");
// ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
}
return View();
}
In the View just have
#using (Html.BeginForm())
Here is a link about MVC Razor Forms: http://blog.michaelckennedy.net/2012/01/20/building-asp-net-mvc-forms-with-razor/
Try that.
The problem was with my Views and which views I was returning. I was trying to use my Index view for validation, I hadn't created a Login View, so once I did that and added my validation to the Login View it worked. So in my question, Return View() wasn't really returning anything
Related
I am developing a simple asp.Net MVC application which needs FormsAuthentication,
Model
public class Member
{
[Required]
[Display(Name = "Username")]
public string Username { set; get; }
[Required]
[Display(Name = "Password")]
public string Password { set; get; }
[Display(Name = "Remember Me?")]
public bool RemeberMe { set; get; }
public bool IsValid(string username,string password)
{
return (new TestdbEntities()).Members.Any(m => m.Username == username && m.Password == password);
}
}
Controller
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(Models.Member member)
{
if (ModelState.IsValid)
{
if (member.IsValid(member.Username, member.Password))
{
FormsAuthentication.SetAuthCookie(member.Username,member.RemeberMe);
return RedirectToAction("Index","Home");
}
else
{
ModelState.AddModelError("","Invalid Username/Passowrd!");
}
}
return View(member);
}
View
The problem occurres in view, which I expect the Login link changed to Logout link when the user successfully authenticated, but even when I trace, the login is successful but Request.IsAuthenticated is false.
<body>
<ul class="nav nav-pills">
<li>
#Html.ActionLink("Home", "Index", "Home")
</li>
<li>
#if (Request.IsAuthenticated)
{
<label>Welcome </label> #Html.Encode(User.Identity.Name)
#Html.ActionLink("Signout", "Logout", "Membership")
#Html.Label(User.Identity.Name.ToString())
}
else
{
#Html.ActionLink("Login", "Login", "Membership")
}
</li>
</ul>
<div>
#RenderBody()
</div>
</body>
Check your web.config file,you must add <authentication mode="Forms"/> under <system.web> tag
Use the following:
User.Identity.IsAuthenticated()
Let me explain a bit what I am trying to achieve . I have a View which has to Partial Views in it and each Partial Views have two different models .
1- LoginViewModel
2- RegisterViewModel
All i want to achieve is when the Login Post action occurs only Login Model to be returned to the Partial View with All validation messages if any field is left empty .
I am having a problem when I return the same view when there is any error in validating the fields .
Here is the piece of code
Account Controller:
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = User.SelectByUserNameAsync(model.UserName,model.Password);
if (user != null)
{
// var x = User.SignInAsync(model);
return Redirect("Home/Index");
}
else
{
ViewBag.Model = new RegisterViewModel();
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
LoginView :
#{
Layout = "~/Views/Shared/_LoginLayout.cshtml";
}
<section id="page-title">
<div class="container clearfix">
<h1>My Account</h1>
<ol class="breadcrumb">
<li>Home</li>
<li>Sign-Up</li>
<li class="active">Login</li>
</ol>
</div>
</section><!-- #page-title end -->
<!-- Content
============================================= -->
<section id="content">
<div class="content-wrap">
<div class="container clearfix">
<!--Login PartialView-->
#{Html.RenderPartial("_LoginBox");}
<!--Login PartialView Ends-->
<!--Register PartialView-->
#{Html.RenderPartial("_Register");}
<!--Register PartialView Ends-->
</div>
</div>
</section><!-- #content end -->
but when the page returns if any error is occured it shows me the error
The model item passed into the dictionary is of type 'ConnexMi.Models.LoginViewModel', but this dictionary requires a model item of type 'ConnexMi.Models.RegisterViewModel'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'ConnexMi.Models.LoginViewModel', but this dictionary requires a model item of type 'ConnexMi.Models.RegisterViewModel'.
Source Error:
Line 28:
Line 29: <!--Register PartialView-->
Line 30: #{Html.RenderPartial("_Register");}
Line 31:
Line 32: <!--Register PartialView Ends-->
Can you please tell me what I am doing wrong in this code ? Thanks
You will need a view model that combines both the Login and Register view models. For example
View models
public class LoginVM
{
[Display(Name = "Email")]
[Required(ErrorMessage = "Please enter an email address")]
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string Email { get; set; }
[Required(ErrorMessage = "Please enter a password")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
}
public class RegisterVM
{
// properties for email, password and confirm password
}
public class LoginRegisterVM
{
public LoginVM Login { get; set; }
public RegisterVM Register { get; set; }
}
Controller (assume Account)
public ActionResult Index()
{
LoginRegisterVM model = new LoginRegisterVM();
return View(model);
}
[HttpPost]
public ActionResult Login([Bind(Prefix="Login")]LoginVM loginModel)
{
if (!ModelState.IsValid)
{
LoginRegisterVM model = new LoginRegisterVM();
model.Login = loginModel;
return View("Index", model);
}
// Login and redirect
}
[HttpPost]
public ActionResult Register([Bind(Prefix="Register")]RegisterVM registerModel)
{
if (!ModelState.IsValid)
{
LoginRegisterVM model = new LoginRegisterVM();
model.Register = registerModel;
return View("Index", model);
}
// Register and redirect
}
View
#model LoginRegisterVM
#using(Html.BeginForm("Login", "Account", FormMethod.Post)
{
#Html.LabelFor(m => m.Login.Email)
#Html.TextBoxFor(m => m.Login.Email)
#Html.ValidationMessageFor(m => m.Login.Email)
... // other properties of login model
<input type="submit" value="Login" />
}
#using(Html.BeginForm("Register", "Account", FormMethod.Post)
{
// properties of register model
<input type="submit" value="Register" />
}
Hi I want To Make one Login Page For Members And Admin Also..
Here I have done the Following Code as:
In Model:
public class Login
{
public int ID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
controller
[HttpPost]
public ActionResult Login(Login login, MemberDetailsWrapper memberlogin)
{
WrapperDB db = new WrapperDB();
if (login.UserName.Equals("admin") &&login.Password.Equals("admin")) //This will check for admin
{
returnRedirectToAction("Index");
}
else if
(
(login.UserName.Equals(memberlogin.objMemberBasicInformation.MemberFirstName.Equals(db.MemberBasicInformationDBS.Where(a =>a.MemberFirstName.Equals(a.MemberFirstName))))
&& (login.Password.Equals(memberlogin.objMemberBasicInformation.Qualification.Equals(db.MemberBasicInformationDBS.Where(a=>a.Qualification.Equals(a.Qualification))))))
)
//This is For Member Login When Member Enter His FistName as a userName and Qualification as Password then Both credential match with the data present in db and return the respected person information
{
return RedirectToAction("Index","MemberDetails");
}
ModelState.AddModelError("", "UserName And Password is Incorrect!!");
return View();
}
In view :
<%#PageTitle=""Language="C#"Inherits="System.Web.Mvc.ViewPage<SHGManagementProject.Models.Login>"%>
<h2>Login</h2>
<%using (Html.BeginForm("Login", "Home", FormMethod.Post))
{ %>
<%:Html.ValidationSummary(true) %>
<fieldset>
<legend>Log in Form</legend>
<div>
UserName
<%:Html.TextBoxFor(m=>m.UserName) %>
</div>
<br/>
<div>
Password
<%:Html.PasswordFor(m=>m.Password) %>
</div>
<br/>
<div>
<inputid="SubmitLogin"type="submit"value="Login"/>
<%--<%:Html.ActionLink("Are you Member? click Here!!","Login","Account") %>--%>
</div>
</fieldset>
<%} %>
On execution When i Enter the Username and Pass as admin then it will perform successfully.. but when i enter the another username and password then it throws Error NullReferenceException was Unhandled by User code
please tell me the solution and help me to solve this
Without knowing where your code is throwing the error, I'm assuming the issue is down to memberLogin parameter?
[HttpPost]
public ActionResult Login(Login login, MemberDetailsWrapper memberlogin)
{
WrapperDB db = new WrapperDB();
if (login.UserName.Equals("admin") &&login.Password.Equals("admin")) //This will check for admin
{
returnRedirectToAction("Index");
}
else if (memberlogin != null)
{
if
(
(login.UserName.Equals(memberlogin.objMemberBasicInformation.MemberFirstName.Equals(db.MemberBasicInformationDBS.Where(a =>a.MemberFirstName.Equals(a.MemberFirstName))))
&& (login.Password.Equals(memberlogin.objMemberBasicInformation.Qualification.Equals(db.MemberBasicInformationDBS.Where(a=>a.Qualification.Equals(a.Qualification))))))
)
{
return RedirectToAction("Index","MemberDetails");
}
else
{
ModelState.AddModelError("", "UserName And Password is Incorrect!!");
return View();
}
}
ModelState.AddModelError("", "UserName And Password is Incorrect!!");
return View();
}
I've added a check against memberlogin to check if it's null, double check the parenthesis though, as I've just typed this by hand.
In MVC4, a controller named UserController contains an action ForgotPassword and a respective view is also created. This view contains one textbox and one submit button. On the submit of this button the email id should be verified, if not found in record, it should show a error message on the same view, else navigate to different view.
I have used Begin Form for mapping the submit button to a new action VerifyEmailId in UserController. However I am stuck on passing the view based on the validity of the email id. Note that this action VerifyEmailId does not have any related view.
Please suggest the best way to do it.
View Code:
#model UIKendoLearning.Models.UserDetails
<h2>Forgot Retrieval</h2>
#using (Html.BeginForm("ForgotPassword", "User"))
{
<div id="PasswordRetrieval">
#Html.Label("Please enter your registered email address: ")
<input type="email" id="Email" value="#Model.Email" name="Email" placeholder="e.g. myname#example.net" />
#Html.ValidationMessageFor(m => m.Email)
<br />
<input type="submit" name="Submit" value="Generate New Password" />
</div>
}
Controller Code:
public class UserController : Controller
{
//
// GET: /User/
public ActionResult ForgotPassword()
{
return View(new UserDetails());
}
[HttpPost]
public ActionResult SendNewPassword(UserDetails userInfo)
{
try
{
if (userInfo != null)
{
HttpClient server = new HttpClient();
server.DefaultRequestHeaders.Add("EmailId", userInfo.Email);
HttpResponseMessage response = server.GetAsync("http://localhost/BankService/api/Account/ValidateUser").Result;
if (response.StatusCode != HttpStatusCode.Found)
{
return RedirectToAction("ForgotPassword", "User");
}
}
}
catch (Exception ee)
{
}
return RedirectToAction("Index", "Home");
}
I have a similar implementation, I suggest you don't need a new Action ValidateEmailID, but only a bool function that you can call from the ForgotPassword Post Action.
This could be the Controller code:
//
// GET: /User/ForgotPassword
[AllowAnonymous]
public ActionResult ForgotPassword()
{
return View();
}
//
// POST: /User/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ForgotPassword(String email)
{
if (ModelState.IsValid)
{
if (verifyEmailId(email))
{
// Do something, i.e. send email with proper instruction
// Display a view to say action is done!
return View("ConfirmReset");
// Or redirect to another action:
return RedirectToAction("ActionName", "ControllerName");
}
else
{
// Add an error message
ModelState.AddModelError("", "The email ID you submitted is unknown");
}
}
// Redisplay the ForgotPassword View with error message, preserving the submitted email value
ViewBag.email = email;
return View();
}
private bool verifyEmailId(email) {
// Your own code
// return true if email is valid
}
And this could be the ForgotPassword View code:
<p>Please submit the email address to reset the password</p>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()
#Html.Label("email")
#Html.Editor("email")
<input type="submit" value="Reset Password" />
}
I hope this could be usefull for you.
Modify your method
#model UIKendoLearning.Models.UserDetails
<h2>Forgot Retrieval</h2>
#using (Html.BeginForm("ForgotPassword", "User"))
{
<div id="PasswordRetrieval">
#ViewBag.Error **// Your Error comes here**
#Html.Label("Please enter your registered email address: ")
<input type="email" id="Email" value="#Model.Email" name="Email" placeholder="e.g. myname#example.net" />
#Html.ValidationMessageFor(m => m.Email)
<br />
<input type="submit" name="Submit" value="Generate New Password" />
</div>
}
Controller
public ActionResult ForgotPassword()
{
if (Request.QueryString["error"] != null)
ViewBag.Error = "Email Not Found";
else
ViewBag.Error = "";
return View(new UserDetails());
}
[HttpPost]
public ActionResult SendNewPassword(UserDetails userInfo)
{
try
{
if (userInfo != null)
{
HttpClient server = new HttpClient();
server.DefaultRequestHeaders.Add("EmailId", userInfo.Email);
HttpResponseMessage response = server.GetAsync("http://localhost/BankService/api/Account/ValidateUser").Result;
if (response.StatusCode != HttpStatusCode.Found)
{
return RedirectToAction("ForgotPassword", "User",new{error="notFound"});
}
}
}
catch (Exception ee)
{
}
return RedirectToAction("Index", "Home");
}
As #Doan Cuong wrote it is good solution to use content validity. For example, you have model for your view like this:
class UserDetails
{
[DataType(DataType.EmailAddress)]
[Required(ErrorMessage = "Please enter a proper email address")]
public string Email { get; set; }
// property for displaying custom error message if validation failed
public string ErrorMessage { get; set; }
...
}
You have a form which calls action ForgetPassword. SendNewPassword should be renamed to ForgetPassword. And if you using try/catch it will be good if you display something if error occures. So, the controller code may look like this:
class UserController
{
[NonAction]
private bool VerifyEmail(string email)
{
// ... verify logic
}
public ActionResult ForgotPassword()
{
return View(new UserDetails());
}
[HttpPost]
public ActionResult ForgotPassword(UserDetails userInfo)
{
if (ModelState.IsValid)
{
// Here is userInfo.Email is a proper email address
if(VerifyEmail(userInfo.Email)
{
HttpClient server = new HttpClient();
server.DefaultRequestHeaders.Add("EmailId", userInfo.Email);
HttpResponseMessage response = server.GetAsync("http://localhost/BankService/api/Account/ValidateUser").Result;
if (response.StatusCode != HttpStatusCode.Found)
{
// Here is error action ForgotPassword with param with field "error"
// return RedirectToAction("ForgotPassword", "User",new{error="notFound"});
return View("ForgotPassword", "User", new UserDetails { ErrorMessage = "Email not found" } );
}
// Here is all ok - go home
return RedirectToAction("Index", "Home");
}
}
// Redisplay form with error messages
return View(model);
}
}
And modify the View code:
#model UIKendoLearning.Models.UserDetails
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<h2>Forgot Retrieval</h2>
#using (Html.BeginForm("ForgotPassword", "User"))
{
<div id="PasswordRetrieval">
#Html.Label("Please enter your registered email address: ")
<input type="email" id="Email" value="#Model.Email" name="Email" placeholder="..." />
#Html.ValidationMessageFor(m => m.Email)
#if(Model.ErrorMessage != null)
{
#* you can insert some good html *#
<span>#Model.ErrorMessage</span>
}
<br/>
<input type="submit" name="Submit" value="Generate New Password" />
</div>
}
I have the following View code:
#using (Html.BeginForm("Login", "Press", FormMethod.Post))
{
<fieldset>
<legend>User Registration</legend>
<div>
#Html.TextBoxFor(model => model.FullName)
#Html.ValidationMessageFor(model => model.FullName)
</div>
<div>
#Html.TextBoxFor(model => model.Company)
#Html.ValidationMessageFor(model => model.Company)
</div>
<div>
#Html.TextBoxFor(model => model.EmailAddress)
#Html.ValidationMessageFor(model => model.EmailAddress)
</div>
<div>
#Html.CheckBoxFor(model => model.JoinMailingList)
Please check this box to recieve a seasonal look book pdf and monthly newsletter
</div>
<p>
<input type="submit" value="Proceed" />
</p>
</fieldset>
}
And here is my Model:
public class UserViewModel
{
[Required(ErrorMessage = "Please enter your name.")]
[MaxLength(100)]
public string FullName { get; set; }
[Required(ErrorMessage = "Please enter the name of your company.")]
[MaxLength(50)]
public string Company { get; set; }
[Required(ErrorMessage = "Please enter your email.")]
[DataType(DataType.EmailAddress)]
[RegularExpression(#"^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A-Za-z0-9]+#((\w+\-+)|(\w+\.))*\w{1,63}\.[a-zA-Z]{2,6}$", ErrorMessage = "Please enter a valid email address.")]
[MaxLength(255)]
public string EmailAddress { get; set; }
public bool JoinMailingList { get; set; }
}
The problem is that when I click on the 'Proceed' button, none of the validation occurs. It just posts the action with no validation performed on it? Do I have to perform this inside the Controller?
Here is my Controller code:
public class PressController : Controller
{
//
// GET: /Press
public ViewResult Index()
{
return View();
}
//
// GET: /Press/Login
public ViewResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(UserViewModel userViewModel)
{
return RedirectToAction("Index", "Press");
}
}
Make sure that the action you are posting to takes the view model as argument:
[HttpPost]
public ActionResult Press(UserViewModel model)
{
// at this stage the validation has been performed during
// the process of model binding and now you could look in the
// modelstate if the model is vaild:
if (!ModelState.IsValid)
{
// validation failed => redisplay the view so that the user
// can fix his errors.
// Note that calling ModelState.IsValid doesn't trigger any validation
return View(model);
}
// at this stage we know that validation passed => we could do some processing
// and redirect
return RedirectToAction("Success");
}
or some people also use the TryUpdateModel method which also allows you to perform model binding which triggers the validation:
[HttpPost]
public ActionResult Press()
{
var model = new UserViewModel();
// validation will be triggered at this stage and the method
// will return true or false based on the result of this validation
if (!TryUpdateModel(model))
{
// validation failed => redisplay the view so that the user
// can fix his errors.
return View(model);
}
// at this stage we know that validation passed => we could do some processing
// and redirect
return RedirectToAction("Success");
}
And if you want to enable client side validation, just make sure that the following 2 scripts are referenced in your page:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
Do you have the client-validation enabled?
See "Step 3: Enabling Client-side Validation" in ScottGu's post
In the server side you must check is the model valid using
ModelState.IsValid