In my application I am trying to get a forgot password to work. I am trying to send an email to the user when he/she inputs his or her user name, sends them and email, they click on that link, and are brought back into the website and changes their password. Only thing is that my linq query is wrong an is not checking to see if the username exists in the database. Is this the right way to go by getting a forget password to work?
Here is my code
Controller
// GET: /Account/ForgotPassword
[AllowAnonymous]
public ActionResult ForgetPassword()
{
return View();
}
// Post: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ForgetPassword(ForgetPasswordModel model, string UserName)
{
string emailAddress = (from i in db.UserProfiles
where i.UserName.Equals(model.Username)
select i.Email).Single();
if (!string.IsNullOrEmpty(emailAddress))
{
string confirmationToken =
WebSecurity.GeneratePasswordResetToken(model.Username);
dynamic email = new Email("ChngPasswordEmail");
email.To = emailAddress;
email.UserName = model.Username;
email.ConfirmationToken = confirmationToken;
email.Send();
return RedirectToAction("ResetPwStepTwo");
}
return RedirectToAction("InvalidUserName");
}
Model
public class ForgetPasswordModel
{
[Required]
[Display(Name = "Username")]
public string Username { get; set; }
}
View
#model MyFestival.Models.UserProfile
#{
ViewBag.Title = "Forgot Password";
}
<hr />
<div class="form-group">
<h3 class="panel-title">Did you forget your password?</h3>
</div>
#using (Html.BeginForm())
{
<div class="">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, null, new { #style = "color:red;" })
<hr />
<label>To reset your password, input your email address and press the Reset Password button.</label>
<br/>
<div class="form-group" >
<div class="col-md-12" >
<div class="input-group">
<span class="input-group-addon" ><i class="glyphicon glyphicon-user" ></i ></span >
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control", #placeholder = "Username" })
</div >
#Html.ValidationMessageFor(m => m.UserName, null, new { #style = "color:red;" })
</div>
</div>
<br/>
<br/>
<div class="form-group" >
<div class="col-md-offset-2 col-md-10" >
<input type="submit" class="btn btn-default" value="Reset Password"/ >
#Html.ActionLink("Back to Login", "Login", null, new { #class = "btn btn-info" })
</div >
</div>
</div>
}
I've just spotted that you have both ForgetPasswordModel model and string username as arguments of your controller action and later you use Username property of your model. I assume that Model Binder just initializes the stirng username instead of ForgegPasswordModel. Could you try removing stirng username - the second parameter of ForgetPassword action?
You can create your own GUID and send it with email to user.
When user click on email link check Guid and update new password of user.
Here is the sample code
Create a view to enter forgot password email
#{
ViewBag.Title = "Forgot Password";
}
<h2>Forgot Password</h2>
#using (Html.BeginForm())
{
<div class="form-horizontal">
<hr />
<div class="text-success">
#ViewBag.Message
</div>
<div class="form-group">
Please enter your registered email address below to receive an email containing a link, to reset your password.
</div>
<div class="form-group">
<label class="control-label col-md-2">Email Address</label>
#Html.TextBox("EmailID", "", new { #class = "form-control" })
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" class="btn btn-success" />
</div>
</div>
</div>
}
Then in your Controller get Email id from user, check if email exists and create new GUID, save it in database, send email to user.
[HttpPost]
public ActionResult ForgotPassword(string EmailID)
{
string resetCode = Guid.NewGuid().ToString();
var verifyUrl = "/Account/ResetPassword/" + resetCode;
var link = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery, verifyUrl);
//get user details from database.
using (var context = new LoginRegistrationInMVCEntities())
{
var getUser = (from s in context.RegisterUsers where s.Email == EmailID select s).FirstOrDefault();
if (getUser != null)
{
getUser.ResetPasswordCode = resetCode;
//This line I have added here to avoid confirm password not match issue , as we had added a confirm password property
context.Configuration.ValidateOnSaveEnabled = false;
context.SaveChanges();
var subject = "Password Reset Request";
var body = "Hi " + getUser.FirstName + ", <br/> You recently requested to reset your password for your account. Click the link below to reset it. " +
" <br/><br/><a href='" + link + "'>" + link + "</a> <br/><br/>" +
"If you did not request a password reset, please ignore this email or reply to let us know.<br/><br/> Thank you";
SendEmail(getUser.Email, body, subject);
ViewBag.Message = "Reset password link has been sent to your email id.";
}
else
{
ViewBag.Message = "User doesn't exists.";
return View();
}
}
return View();
}
private void SendEmail(string emailAddress, string body, string subject)
{
using (MailMessage mm = new MailMessage("youremail#gmail.com", emailAddress))
{
mm.Subject = subject;
mm.Body = body;
mm.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.EnableSsl = true;
NetworkCredential NetworkCred = new NetworkCredential("youremail#gmail.com", "YourPassword");
smtp.UseDefaultCredentials = true;
smtp.Credentials = NetworkCred;
smtp.Port = 587;
smtp.Send(mm);
}
}
Now, when user click on the email and enter new password, check Guid with what we have saved in database and update password if guid matches.
Check for more info:
Forgot password functionality in ASP.NET MVC (Reset password by Email)
Related
I have modified the Views/Manage/Index.cshtml to display the User's email as well. I've modified the IndexViewModel as well so it recognizes the "Email" string and then made another .cshtml page similar to the changing of phone number one which is there by default. The new page is called ChangeEmail.cshtml
#using (Html.BeginForm("ChangeEmail", "Manage", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Add an email</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
From what I've seen, the changing of password happens through a task called "ChangePasswordAsync" inside UserManager.cs
Is there a way to change the Email without making a new task?
EDIT: added more from the controller(index) :
public async Task<ActionResult> Index(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
: message == ManageMessageId.EmailChangedSuccess ? "Your email has been changed"
: "";
var userId = User.Identity.GetUserId();
var userEmail = User.Identity.Name;
var user = UserManager.FindById(userId);
var model = new IndexViewModel
{
HasPassword = HasPassword(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
Logins = await UserManager.GetLoginsAsync(userId),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId),
Email = user.Email,
City = user.City,
Region = user.Region
};
user.Email = "topkek#ucn.dk";
UserManager.UpdateAsync(user);
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeEmail(ChangeEmailViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
return RedirectToAction("Index", new { Message = ManageMessageId.EmailChangedSuccess });
}
Get the user's Email address from your ChangeEmailViewModel and then update the user's details using the userManager.UpdateAsync(user)
EDIT
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ChangeEmail(ChangeEmailViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
//Get the user's Id
var userId = User.Identity.GetUserId();
//get the user (you can modify the variables to fit yours)
var user = UserManager.FindByIdAsync(userId);
//this is how to change the Email
user.Result.Email= model.Email// **EDIT**;
userManager.UpdateAync(user.Result);
return RedirectToAction("Index", new { Message = ManageMessageId.EmailChangedSuccess });
}
Im making a homepage in which i want to have a form that ppl can fill in and then when clicking submit have it sent to a gmail account. I more or less want it to show up as an email without them having to fill in their own email address. I was thinking it would work out fine just sending it from the same email that is receiving it.
Problem is that it wont really get trough.
The procedure is fine since i can see all the information i fill in correctly but it wont send the mail.
This is the controller:
public ActionResult InvitationResponseForm()
{
return View();
}
[HttpPost]
public ViewResult InvitationResponseForm(InvitationResponse model)
{
if (ModelState.IsValid)
{
MailMessage response = new MailMessage();
response.From = new MailAddress("sixtofjun#gmail.com");
response.To.Add("sixtofjun#gmail.com");
response.Subject = model.Name + " " + model.Surname;
string Special = model.SpecialConditions;
string PlusOne = model.PlusOneComment;
bool OneOrTwo = model.PlusOne;
response.Body = model.Name + " " + model.Surname + " " + OneOrTwo + "<br><br>" + Special + "<br>" + PlusOne;
response.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient("smtp.gmail.com", 465);
NetworkCredential basicAuthInfo = new NetworkCredential("sixtofjun#gmail.com", "My password");
smtp.UseDefaultCredentials = false;
smtp.Credentials = basicAuthInfo;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.EnableSsl = true;
return View("InvitationResponseForm", model);
}
else
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
return View();
}
}
And some of the view:
<div class="form-group">
#Html.LabelFor(model => model.PlusOneComment, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PlusOneComment)
#Html.ValidationMessageFor(model => model.PlusOneComment)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SpecialConditions, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SpecialConditions)
#Html.ValidationMessageFor(model => model.SpecialConditions)
</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>
Doing this for my pending wedding so really would like some help with it!
Feel free to ask for more info!
Tried alot now but still nothing successful. Can it have something to do with my ssl?
Your gmail smtp port is wrong. You use "smtp.EnableSsl = true;" but still use the 465 port. I use this code and it is sending emails:
var client = new SmtpClient("smtp.gmail.com", 587)
{
Credentials = new NetworkCredential("myusername#gmail.com", "mypwd"),
EnableSsl = true
};
client.Send("myusername#gmail.com", "myusername#gmail.com", "test", "testbody");
I have a DropDownListFor on my view. In fact I have 3, out of three of them only two of them work. Despite being almost exactly the same code, my get around at the moment is to create an input box and populate it on click of a button with the value from the drop down box(strange I know, I can get the value using JQuery). I've checked and all names seem to be the same so I'm really not sure why it doesn't submit.
View:
<content id="GenerateReportContent" class="col-lg-4 col-md-4 col-sm-12 col-xs-12">
#using (Html.BeginForm("ReportSelection", "Search", FormMethod.Post, new { #id = "GenerateReportContainer" })) {
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="AltFunctions">
<ul>
<li>
<a href="javascript:document.getElementById('GenerateReportContainer').reset();" class="AltButton" id="altClearButton" title="Reset the 'Generate Report' container" >Clear</a>
</li>
<li>
Info
</li>
</ul>
</div>
<h1 id="GenerateReportHeader">SEARCH ENGINE</h1>
</div>
<input type="hidden" name="ClientID" value="#Model.ClientID" id="Client" />
<input type="hidden" name="ClientName" value="#Model.ClientName" id="ClientName" />
<input type="hidden" name="SupplierFound" value="#Model.SupplierFound" id="SupplierFound" />
#Html.TextBoxFor(m => m.ClaimNo, "", new { #id = "txtGRCSelect", #class = "form-control", placeholder = "Enter Specific Claim Number..." })
<br />
<div class="ui-widget">
#Html.TextBox("SupplierAuto", "", new { #id = "SupplierAutotxt", #class = "form-control SupplierAutoComplete", placeholder = "Search for a supplier name" })
</div>
#Html.DropDownListFor(m => m.SupplierID, new SelectList(Model.Suppliers, "SupplierID", "DisplayName"), "Select Supplier Name", new { #id = "SuppNameDD", #class = "GRDropDown"})
<br />
<!-- THE DROP DOWN IN QUESTION-->
#Html.DropDownListFor(m => m.GroupModelClass.GroupID, new SelectList(Model.GroupModelClass.ClaimGroups, "GroupID", "GroupName"), "Select Supplier Group Name", new { #id = "SuppGroupDD", #class = "GRDropDown" })
<br />
#Html.DropDownListFor(m => m.ReviewPeriodID, new SelectList(Model.ReviewPeriods, "ReviewPeriodID", "ReviewPeriodName"), "Select Review Period", new { #id = "ReviewPeriodDD", #class = "GRDropDown" })
// Have to submit this field at the moment as the drop down value is not being submitted
<input hidden id="GroupIDInput" name="GroupIDInput" />
<br />
<br />
<button type="submit" value="Submit" id="GenerateReportButton" class="btn btn-default">GO</button>
<div id="ErrorBox" hidden>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class="sr-only">Error:</span>
<p id="ErrorBoxText"></p>
</div>
</div>
}
</content>
Controller:
public ActionResult ReportSelection(int ClientID, string ClaimNo, string SupplierAuto, int? SupplierID = null, int? ReviewPeriodID = null, int? GroupID = null) {
if (SupplierAuto != "") {
var Suppliers = suppRepo.GetAllSuppliersByClientWithClaims(ClientID);
foreach (var item in Suppliers) {
if (item.DisplayName == SupplierAuto) {
SupplierID = item.SupplierID;
break;
}
}
if (SupplierID == null) {
return RedirectToAction("Index", "Dashboard", new { ClientID = ClientID });
}
}
client = clientRepo.GetClientNameByID(ClientID);
if (SupplierID != null || ReviewPeriodID != null || GroupIDInput != null) {
return RedirectToAction("SupplierReportSelection", new { ClientID = ClientID, SupplierID = SupplierID, ReviewPeriodID = ReviewPeriodID, ClaimIDs = ClaimIDs });
}
else {
return RedirectToAction("ClaimNumberReportSelection", new { ClientID = ClientID, ClaimNo = ClaimNo });
}
}
Anyone know why it doesn't work?
Use FormCollection:
[HttpPost]
public ActionResult ShowAllMobileDetails(MobileViewModel MV,FormCollection form)
{
string strDDLValue = form["<your-dropdown-name>"].ToString();
return View(MV);
}
If you want with Model binding then add a property in Model:
public class MobileViewModel
{
public List<tbInsertMobile> MobileList;
public SelectList Vendor { get; set; }
public string SelectedVender {get;set;}
}
and in View:
#Html.DropDownListFor(m=>m.SelectedVender , Model.Vendor, "Select Manufacurer")
and in Action:
[HttpPost]
public ActionResult ShowAllMobileDetails(MobileViewModel MV)
{
string SelectedValue = MV.SelectedVendor;
return View(MV);
}
Check with fiddler or F12, but I'm betting m.GroupModelClass.GroupID is getting passed to the model binder as simply GroupID and it has no idea that it's supposed to map to GroupModelClass.GroupID. Try flattening your model a bit?
Im trying to send an email to a user when they have forgot their password in a mvc app this is my code.pls help
this is my email class in my businesslogic
public class EmailBusiness
{
public bool SendEmailForgot(string email, string url)
{
bool isvalid = false;
try
{
var boddy = new StringBuilder();
boddy.Append("Hi! " + email + "<br/>");
boddy.Append("Click the link to reset your " + url);
string bodyFor = boddy.ToString();
string toFor = email;
const string subjectFor = "Reset Password";
WebMail.SmtpServer = "pod51014.outlook.com";
WebMail.SmtpPort = 587;
WebMail.UserName = "20822526#dut4life.ac.za";
WebMail.Password = "Password";
WebMail.From = "20822526#dut4life.ac.za";
WebMail.EnableSsl = true;
WebMail.Send(to: toFor, subject: subjectFor, body: bodyFor);
isvalid = true;
return isvalid;
}
catch
{
return isvalid;
}
}
this is my forgotpassword model in my Accountviewmodels
public class ForgotPasswordViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
}
this is my forgotpassword action in accountcontroller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model, string sms)
{
EmailBusiness _emailBusiness = new EmailBusiness();
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here");
_emailBusiness.SendEmailForgot(model.Email, callbackUrl);
return RedirectToAction("ForgotPasswordConfirmation", "Account");
}
// If we got this far, something failed, redisplay form
return View(model);
}
and this is my view
#model Template.Model.ForgotPasswordViewModel
#{
ViewBag.Title = "Forgot your password?";
Layout = "~/Views/shared/_BootstrapLayout.basic.cshtml";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Enter your email.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Email Link" />
</div>
</div>
}
and this in my webconfig
<appSettings>
<add key="from" value="20822526#dut4life.ac.za" />
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
I've created a new Web Forms Project in visual studio 2013 and I want users to be able to login using their UserName(eg. administrator) not their email address.
If you open the automatically generated "Register.aspx.cs" file you'll see this piece of code:
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text };
Question:
Why does the UserName and Email have the same value on last line??? In this case why do you need UserName column since you have already Email column?
Is possible to login using username not email address?
I'm trying to solve this by adding a new textbox field to registration form called "UserName":
Register.aspx
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="UserName" CssClass="col-md-2 control-label">UserName</asp:Label>
<div class="col-md-10">
<asp:TextBox runat="server" ID="UserName" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="Email"
CssClass="text-danger" ErrorMessage="The UserName field is required." />
</div>
</div>
And on the Register function I've made this change:
Register.aspx.cs
var user = new ApplicationUser() { UserName = UserName.Text, Email = Email.Text };
Then I've changed the login function like this:
Login.aspx.cs
protected void LogIn(object sender, EventArgs e)
{
if (IsValid)
{
// Validate the user password
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
// This doen't count login failures towards account lockout
// To enable password failures to trigger lockout, change to shouldLockout: true
//var result = signinManager.PasswordSignIn(Email.Text, Password.Text, false, shouldLockout: false);
SignInStatus result = SignInStatus.Failure;
// check too see if the user has entered a email address or not
if (IsValidEmail(NameOrEmail.Text))
{
result = signinManager.PasswordSignIn(NameOrEmail.Text, Password.Text, false, shouldLockout: false);
}
else
{
// get users email using his name
var user = manager.FindByName(NameOrEmail.Text);
result = signinManager.PasswordSignIn(user.Email, Password.Text, false, shouldLockout: false);
}
switch (result)
{
case SignInStatus.Success:
string queryString = Request.QueryString["ReturnUrl"];
if (!string.IsNullOrEmpty(queryString))
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
else
Response.Redirect("/Account/Dashboard");
break;
case SignInStatus.LockedOut:
Response.Redirect("/Account/Lockout");
break;
case SignInStatus.Failure:
default:
FailureTextLabel.Text = "Invalid login!";
ErrorMessage.Visible = true;
break;
}
}
}
// check email address
private bool IsValidEmail(string strIn)
{
// Return true if strIn is in valid e-mail format.
return Regex.IsMatch(strIn, #"^([\w-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
}
And the template looks like this:
Login.aspx
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="NameOrEmail" CssClass="col-md-2 control-label">UserName or Email</asp:Label>
<div class="col-md-10">
<asp:TextBox runat="server" ID="Email" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="NameOrEmail"
CssClass="text-danger" ErrorMessage="The name or email field is required." />
</div>
</div>
The problem:
If you change the UserName on Register you cannot login anymore(you'll get SignInStatus.Failure).
Seems to me that the UserName has to be the same as Email on registration for the login to work.
Is there a way to solve this?
First of all this isn't a bug at all. This is how it works, if you want to use out of the box default implementation which created with the visual studio 2013 template (with individual users) then you will get it that way.
As developers asp.net identity stuff can be configurable according to our choice. For that you need to go deep into identity framework and understand how it works.
Most of simple yet very important configuration can be found in the IdentityConfig.cs file if you have used visual studio 2013 with update 3 or later.
identity framework version 1 comes with only with username without email address supporting UI, but things changed with the version 2.x and visual studio 2013 update 3 and 4 which included email address for both username and email.
You can change it to use username instead email as explained below.
New out of the box registration code is:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
You can see that the Username and Email both uses model.Email.
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
Update your code as below
Register method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager)
{
RequireUniqueEmail = false,
};
var user = new ApplicationUser { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
RegisterViewModel
public class RegisterViewModel
{
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
LoginViewModel
public class LoginViewModel
{
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
Further you need to update other view models not to use email and instead use username
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
Then update all views to use UserName instead Email like below.
#model WebApplication2.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}