I am creating a web application that contains a model for the user. After creating the model without errors, I'm trying to update the password for the user (Change password form). Every time I try to update the model, the db.savechanges() throw an exception (Title and the category are required although this user has entries for both fields). When I try to debug this controller method, no exceptions are thrown and The user contains data for both the category and the faculty title!!
here is my user model:
[Key]
public int Id { get; set; }
[Required]
[ScaffoldColumn(false)]
[Display(Name = "Email address")]
public string Email { get; set; }
[ScaffoldColumn(false)]
[Required]
public virtual FacultyTitle Title { get; set; }
[Required]
[StringLength(128, MinimumLength = 2, ErrorMessage = "{0} must be less than {1} characters and more than {2} characters.")]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Position")]
[ScaffoldColumn(false)]
[Required]
public virtual Categories Categorie { get; set; }
And here is the part of the method that I am using to update the user password:
user.Password = Helper.EncryptPassword(newPass);
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
The exception message: The title and the categories field are required
Please any one help me
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.
I am new To EntityFramework and Also ASP.Net
I am creating an authentication system in Asp.net MVC5 with EF and i have following fields in my db
Id | Name | Contact | Url | Username | Password
and I have my model Clients.cs with a class Clients that need to be stored in database:
public class Clients
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public long? Contact { get; set; }
[Required]
[Display(Name = "Site Url")]
public string Url { get; set; }
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Required]
[Compare("Password", ErrorMessage = "Password Mismatched. Re-enter your password")]
[DataType(DataType.Password)]
[Display(Name = "Confirm Password")]
public string ConfirmPassword { get; set; }
}
And I try to store the Credentials as shown below:
//Controller::
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Clients clients)
{
if (ModelState.IsValid)
{
Clients client = new Clients();
client.Name = clients.Name;
client.Password = clients.Password;
client.Url = clients.Url;
client.Username = clients.Username;
client.Contact = clients.Contact;
dbContext.Clients.Add(client);
dbContext.SaveChanges();
return RedirectToAction("api/products");
}
return View();
}
It shows an error:
Server Error in '/ProductsApp' Application.
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
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.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Source Error:
Line 32:
Line 33: dbContext.Clients.Add(client);
Line 34: dbContext.SaveChanges();
Line 35: return RedirectToAction("Index");
Line 36: }
How do I store all fields in database except ConfirmPassword field.
Use the NotMappedAttribute:
[NotMapped]
public string MyProperty { get; set; }
Your property will become:
[Required]
[Compare("Password", ErrorMessage = "Password Mismatched. Re-enter your password")]
[DataType(DataType.Password)]
[Display(Name = "Confirm Password")]
[NotMapped]
public string ConfirmPassword { get; set; }
I solved the problem With the Help of Marthijn
I changed the Clients Confirm Password as:
[Compare("Password", ErrorMessage = "Password Mismatched. Re-enter your password")]
[DataType(DataType.Password)]
[Display(Name = "Confirm Password")]
[NotMapped]
public string ConfirmPassword { get; set; }
and Controller's code as:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Clients clients)
{
if (ModelState.IsValid)
{
dbContext.Clients.Add(client);
dbContext.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
and it worked....
Thanks to Marthijn
In the Checkout Controller I have the code
[HttpPost]
public ActionResult AddressAndPayment(FormCollection values)
{
var order = new Order();
TryValidateModel(order);
....
The model looks like this
[Bind(Exclude="OrderId")]
public partial class Order
{
[ScaffoldColumn(false)]
public int OrderId { get; set; }
[ScaffoldColumn(false)]
public string Username { get; set; }
[Required(ErrorMessage= "First Name is required")]
[DisplayName("First Name")]
[StringLength(160)]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last Name is required")]
[DisplayName("Last Name")]
[StringLength(160)]
public string LastName { get; set; }
[Required(ErrorMessage="Address is required")]
[StringLength(70)]
public string Address { get; set; }
[Required(ErrorMessage = "City is required")]
[StringLength(40)]
public string City { get; set; }
[Required(ErrorMessage = "State is required")]
[StringLength(40)]
public string State { get; set; }
[Required(ErrorMessage = "Postal Code is required")]
[DisplayName("Postal Code")]
[StringLength(10)]
public string PostalCode { get; set; }
[Required(ErrorMessage="Country is required")]
[StringLength(40)]
public string Country { get; set; }
[Required(ErrorMessage= "Phone is required")]
[StringLength(24)]
public string Phone { get; set; }
[Required(ErrorMessage="Email Address is required")]
[DisplayName("Email Address")]
[RegularExpression(#"[A-za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}", ErrorMessage="Email is not valid.")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[ScaffoldColumn(false)]
public decimal Total { get; set; }
[ScaffoldColumn(false)]
public DateTime OrderDate { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
I can stop right before the TryValidateModel line and look at form values like
? Request.Form["FirstName"]
"Michael"
? values["FirstName"]
"Michael"
So why does TryValidateModel(order); return false and the order object does not get populated?
Update
To clarify my question I know false means it can not bind but I do not know why it can not bind. Or that it should through the TryValidateModel(or even the ValidateModel)
But what is interesting is that if I change my method signature to
public ActionResult AddressAndPayment(Order order)
order gets populated correctly. So if it is able to bind in the Method call why not TryValidateModel(or even the ValidateModel)?
I am using MVC 4
TryValidateModel returns false when validation of the Form Model against your Orders Model Fails, thus Binding fails.
I hate using
TryValidateModel(order);
and prefer
ValidateModel(order);
early on while developing my page, because binding is a delicate process. This way, if the model fails to bind, I get an exception and an indicative error msg.
I have this data model:
public class User
{
public long UserID { get; set; }
[Required(ErrorMessage = "User name is required.")]
[MaxLength(50, ErrorMessage = "User name cannot be longer than 50 characters.")]
public string UserName { get; set; }
[Email]
[Required(ErrorMessage = "Email is required.")]
[MaxLength(100, ErrorMessage = "Email cannot be longer than 100 characters.")]
public string Email { get; set; }
[Required(ErrorMessage = "Password is required.")]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
public string Password { get; set; }
[MaxLength(150, ErrorMessage = "Full name cannot be longer than 150 characters.")]
public string FullName { get; set; }
public int UserTypeID { get; set; }
public virtual UserType UserType { get; set; }
public virtual ICollection<Page> Pages { get; set; }
}
and I'm using this model to only edit some fields (password shouldn't be editable):
public class EditUserModel
{
public long UserID { get; set; }
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Email]
[Required(ErrorMessage = "Email is required.")]
[MaxLength(100, ErrorMessage = "Email cannot be longer than 100 characters.")]
public string Email { get; set; }
[DataType(DataType.Text)]
[Display(Name = "Full name")]
[MaxLength(150, ErrorMessage = "Full name cannot be longer than 150 characters.")]
public string FullName { get; set; }
public int UserTypeID { get; set; }
public virtual UserType UserType { get; set; }
}
but I'm confused on how to pass the EditUserModel to my data context to update it. Sorry if seems elementary, but I'm really stumped.
This is the auto-generated edit action that I modified:
[IsAdministrator]
[HttpPost]
public ActionResult Edit(EditUserModel user)
{
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.UserTypeID = new SelectList(db.UserTypes, "UserTypeId", "Name", user.UserTypeID);
return View(user);
}
This is the line I'm having trouble with:
db.Entry(user).State = EntityState.Modified;
The reason I created a custom class was to avoid exposing the password from the view.
This can't work because you're trying to save view model.
You could use AutoMapper to rewrite data from view model to your data model. After that you should be able to save changes.
User userModel = Mapper.Map<EditUserModel, User>(user);
userModel = // todo: get password from database
// todo: attach your model to context and save changes
I'm using Entity Framework Code First and that approach works great.
I have a class, employee, in which the user inputs values for the properties on one screen, and then some more on another screen.
The problem I have with this is how to validate these properties?
If I put validation attributes for the properties of the class I have a problem. The validation takes place whether the field is displayed on the form or not.
So for my Employee class I have had to comment out some of the validation in order to get it to work on 1 screen. It probably won't work on the other.
private sealed class Metadata
{
[HiddenInput(DisplayValue=false)]
public int EmployeeId { get; set; }
[DisplayName("Forename")]
[DataType(DataType.Text)]
[Required(ErrorMessage = "Forename is required")]
public string Forename { get; set; }
[DisplayName("Surname")]
[DataType(DataType.Text)]
[Required(ErrorMessage = "Surname is required")]
public string Surname { get; set; }
[DisplayName("Middle Names")]
[DataType(DataType.Text)]
public string Middlenames { get; set; }
//[DisplayName("User Name")]
//[DataType(DataType.Text)]
//[Required(ErrorMessage = "User name is required")]
//public string UserName { get; set; }
[DisplayName("Employee Number")]
[DataType(DataType.Text)]
[Required(ErrorMessage = "EmployeeNumber is required")]
public string EmployeeNumber { get; set; }
[DisplayName("Department")]
[UIHint("DropDownList")]
[Required(ErrorMessage = "You must select a department from a division")]
public int DepartmentId { get; set; }
[DisplayName("User Role")]
[UIHint("DropDownList")]
[Required(ErrorMessage = "You must select a role")]
public int SHP_UserRoleId { get; set; }
//[DisplayName("Email")]
//[DataType(DataType.EmailAddress)]
//[Required(ErrorMessage = "Email is required")]
//[RegularExpression(#"^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$", ErrorMessage = "Not a valid email")]
//[UniqueEmail(ErrorMessage = "User already exists")]
//public string EmailAddress { get; set; }
[DisplayName("End Date")]
public DateTime? EndDate { get; set; }
}
That's a common problem people encounter when they try to use their business models in the views and the reason for this is that business models are closer to the business and the view is closer to the application (it's just a representation of this business model). Today you have two screens, tomorrow maybe three.
For this reason I would recommend you using view models which reflect a given view. So in your case you could have two view models for each view and populate them from the same business model. Validation attributes could be placed on view models. To avoid boilerplate code in converting between your business models and your view models you could use AutoMapper.