I have a asp.net mvc application that uses standard account controller to handle auth.
The client asked me to add new fields as email, city, age to account creation.
Which would be the best way to extend account controller/model?
Should i modify aspnet_users table or should i create a new table with the new fields? Is it a right way to add new fields to AccountFormViewModel?
I guess you have two option:
1) Creating your custom membership provider.
2) Using the builtin profile membership provider
Anyway you have to implement/extend the AccountController and ViewModel that you get with a new MVC project.
If you choose the first option you can add your fields to the aspenet_users table.
If you choose the second option you use the profile table that the framework want you to create.
If you want a "super integration" of your fields you can consider to extend the IIdentity and IPrincipal interfaces. Look at this answer for some more info.
Hope it helps
First you have modify the RegisterModel AcountModels, and add new fileds
public class RegisterModel
{
[Required]
[Display(Name = "User name")]
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; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
in AcountController you modify the Register action
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
using (var context = new ECDB())
{
var username = model.UserName;
var user = context.UserProfiles.SingleOrDefault(u => u.UserName == username);
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Email = model.Email;
context.SaveChanges();
}
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Related
I am new to the asp.net MVC 5 identity framework andI am try to do update my details directly.
Straight forward, What I want to do is to update my user information to the database.
Previously, I changed my user details by using Migrations and I use entity framework in order to generate my controller, view and model it self.
However, How do I update my user details. I have seen role methods..but I never understand, How can I do? without using role..Because,
I want to update all of user information that I needed to do it in UserManageController...
Is it possible? in a different controller and getting values directly on generated user account? How to retrieve then?
Here is my Identity Models
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
public string userFname { get; set; }
public string userLname { get; set; }
public string address { get; set; }
public string userContactNo { get; set; }
public string commercialName { get; set; }
public string commercialAddress { get; set; }
public string commercialEmail { get; set; }
public string userType { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
Here is my Registeration model
public class RegisterViewModel
{
[Required]
[Display(Name = "User First Name")]
public string userFname { get; set; }
[Required]
[Display(Name = "User Last Name")]
public string userLname { get; set; }
[Required]
[Display(Name = "User Address")]
public string address { get; set; }
[Required]
[Display(Name = "User Contact Number")]
public string userContactNo { get; set; }
[Display(Name = "Commercial Name")]
public string commercialName { get; set; }
[Display(Name = "Commercial Address")]
public string commercialAddress { get; set; }
[EmailAddress]
[Display(Name = "Commercial Email")]
public string commercialEmail { get; set; }
[Key]
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { 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; }
[Required]
public string userType { get; set; }
}
How I do this,
UPDATED: As he commented in my answer bellow, he want to update a list of users in the same method. So this will work.
[HttpPost]
public async Task<ActionResult> UpdateUserInfo(List<RegisterViewModel> model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var userStore = new UserStore<ApplicationUser>(new
ApplicationDbContext());
var appManager = new UserManager<ApplicationUser>(userStore);
// here you can do a foreach loop and get the email and assign new datas
foreach(var i in model)
{
var currentUser = appManager.FindByEmail(i.Email);
// here you can assign the updated values
currentUser.userFname = i.userFname;
// and rest fields are goes here
await appManager.UpdateAsync(currentUser);
}
var ctx = userStore.Context;
ctx.SaveChanges();
// now you can redirect to some other method or-else you can return
// to this view itself by returning the data
return RedirectToAction("SomeActionMethod");
}
And yes, you should have the fields in your view and there will be a #Html.BeginForm and a submit button to post your data. Or-else you can post by ajax method
Hope it helps.
Assuming that your ApplicationUser class is part of your Entity Framework DBContext, you can retrieve and update a user like so, using Entity Framework;
var userId = "user id here"; // Set a user ID that you would like to retrieve
var dbContext = new YourDbContext(); // Your entity framework DbContext
// Retrieve a user from the database
var user = dbContext.Set<ApplicationUser>().Find(userId);
// Update a property on your user
user.address = "New value";
// Save the new value to the database
dbContext.SaveChanges();
If you need the userId of the current logged in user, use:
var userId = this.User.Identity.GetUserId();
Multiple users can be retrieved and updated like this:
var dbContext = new YourDbContext();
// Get all users
var users = dbContext.Set<ApplicationUser>().ToList();
foreach (var user in users)
{
user.address = "New value";
}
// Save the new value to the database
dbContext.SaveChanges();
Entity framework will automatically track the changes to each for when you save.
New to MVC. Using Entity Framework and database first.
Problem
-Register page has fields for username, password, confirm password, and e-mail with validators.
-Login page has username and password fields also with validators. Login page asks for confirm password and e-mail when it shouldn't.
Goal
-Fix this, and maybe learn some proper way of using models in the meantime. I have read many articles and seen many videos but a lot use code first, which I am not using. Very confusing to me.
CODE
My User database doesn't have a Confirm Password field so I made a model...
namespace StoreFront.Models
{
[MetadataType(typeof(RegisterViewModel))]
public partial class User
{
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
}
}
My CustomerBaseViewModel has the LoginViewModel and RegisterViewModel that my views should be using...
public class LoginViewModel
{
public int UserID { get; set; }
[DisplayName("Username")]
[Required(ErrorMessage = "Username is required")]
public string UserName { get; set; }
[DisplayName("Password")]
[DataType(DataType.Password)]
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; }
}
public class RegisterViewModel
{
public int UserID { get; set; }
[DisplayName("Username")]
[Required(ErrorMessage = "Username is required")]
public string UserName { get; set; }
[DisplayName("Password")]
[DataType(DataType.Password)]
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; }
[DisplayName("Confirm Password")]
[DataType(DataType.Password)]
[Compare("Password", ErrorMessage = "Passwords must match")]
public string ConfirmPassword { get; set; }
[DisplayName("Email")]
[Required(ErrorMessage = "Email is required")]
[RegularExpression(#"^([a-zA-Z0-9_\-\.]+)#([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$",
ErrorMessage = "Please enter a valid email")]
public string EmailAddress { get; set; }
}
I have two separate controllers...one for login and one for register. Not sure if you need to look at it but I added anyway
public class LoginController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(User user)
{
using (StoreFrontContext db = new StoreFrontContext())
{
if (!ModelState.IsValid)
{
return View();
}
else
{
var usr = db.Users.Where(u => u.UserName.ToLower() == user.UserName.ToLower() && u.Password == user.Password).FirstOrDefault();
if (usr != null)
{
Session["Username"] = usr.UserName.ToString();
Session["UserID"] = usr.UserName.ToString();
}
else
{
ModelState.AddModelError("", "Username or Password is incorrect.");
}
}
}
return View();
}
}
public class RegisterController : Controller
{
StoreFrontContext db = new StoreFrontContext();
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(User account)
{
if (ModelState.IsValid)
{
using (db)
{
bool duplicate = true;
foreach (var name in db.Users)
{
if (account.UserName.ToLower() == name.UserName.ToString().ToLower())
{
ModelState.AddModelError("", "Username already exists in database!");
duplicate = true;
break;
}
else
{
duplicate = false;
}
}
if (!duplicate)
{
account.IsAdmin = false;
account.DateCreated = DateTime.Now;
db.Users.Add(account);
db.SaveChanges();
ModelState.Clear();
}
}
}
return View();
}
}
Login Index() View uses #model StoreFront.Models.LoginViewModel and Register Index() View uses #model StoreFront.Models.RegisterViewModel
I can't seem to figure out what is wrong, but I believe it's what is being passed through the View or the controller. I'm still not very familiar with the Model part of MVC yet..been very struggling on that, so any pointers on that would also help. Any help would be strongly appreciated!!
I am passing login model to mvc4 default login method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && _webSecurity.login(model))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
My Model looks like following
var _loginModel = new LoginModel
{
UserName = abc#gmail.com,
Password = ""
};
but ModelState.IsValid is returning true . I don't know why . Help me
Thanks in advance .
Edit
Here is my LoginModel
public class LoginModel
{
[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 me?")]
public bool RememberMe { get; set; }
}
The validation Attribute defined in the model will be apllied while Model Binding, u don't have to do this manualy.
[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; }
For more complex validation you also could add a regex filter like this:
[RegularExpression(#"^[^\<\>]*$", ErrorMessage = "May not contain <,>")]
This would match windows group policy password filter for example:
(?=^.{6,255}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*
I have added a custom column to my user profile table that is called CoID (int).
When I want to create a new user I want to send the value 1 to CoID, but I am experiencing some trouble and cant get it to work properly.
I am using the standard account tables from mvc4.
Here are some of my code
AccountModel.cs
public class RegisterModel
{
[Required]
[Display(Name = "User name")]
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; }
[DataType(DataType.Custom)]
[Display(Name = "CoID")]
[Compare("CoID", ErrorMessage = "plese insert CoID")]
public int CoID { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public int CoID { get; set; }
}
AccountController.cs
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
model.CoID = 1;
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, model.CoID);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
When executing this code i am getting this error:
The custom Data-type string cannot be null or empty.
I think your call to WebSecurity.CreateUserAndAccount might need looking at.
Perhaps the following might work better:
WebSecurity.CreateUserAndAccount(model.UserName, model.Password,
new { CoID = model.CoID });
As from the anonymous object it can work out what values you're trying to assign to what field names. Otherwise you're just passing through the value and it doesn't know where to put it.
Remove [DataType(DataType.Custom)] or change to [DataType("CoID")].
I'm starting a brand new ASP.NET MVC application using the built in "Internet application" template.
How can I set it up to allow login using email address & password instead of username & password?
If you're using the default AccountModels you might as well change the LogOnModel to remove UserName and add Email, like this:
public class LogOnModel {
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
Change occurrences of UserName to Email in your LogOn view as well.
Finally in your AccountController, change the LogOn action to get the UserName from the email address to complete the SignIn process, like this:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl) {
if (ModelState.IsValid) {
var userName = Membership.GetUserNameByEmail(model.Email);
if (MembershipService.ValidateUser(userName, model.Password)) {
FormsService.SignIn(userName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl)) {
return Redirect(returnUrl);
} else {
return RedirectToAction("Index", "Home");
}
} else {
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
we have same requirement and do this,
you should create custom identity (CustomIdentity : IIdentity, ISerializable)
[Serializable]
public class CustomIdentity : IIdentity, ISerializable
and define Name property for it.
then for get method of name property return email of user
public string Name
{
get{ return Email; }
}
if detail be needed, please comment on this post
Isn't the solution as simple as using the name field as an email address?