In the below code I cannot pass the username to the remote validation function:
public string UserName { get; set; }
public class Numbers
{
[Display(Name = "Additonal Numbers")]
[Remote("NumberExists", "Account", AdditionalFields = "UserName", ErrorMessage = "Serial is already taken.")]
public string additionalNumbers { get; set; }
}
public List<Numbers> NumberList { get; set; }
This is a simple example but I would like to pass additional fields from the same model within a list but I cant seem to access anything outside the scope of the public class.
Do I need to pass the rest of the model into the list in some way to achieve this or am I doing something wrong here?
The AdditionalFields parameter in the remote validation attribute need to be in the same class as the object being validated.
..edit..
public class Numbers
{
public string UserName { get; set; }
[Display(Name = "Additonal Numbers")]
[Remote("NumberExists", "Account", AdditionalFields = "UserName", ErrorMessage = "Serial is already taken.")]
public string additionalNumbers { get; set; }
}
..edit after comments..
It looks like what you want to do is validate that all the numbers are unique for a Username. Try this:
public string UserName { get; set; }
[Display(Name = "Additonal Numbers")]
[Remote("NumberExists", "Account", AdditionalFields = "UserName", ErrorMessage = "Serial is already taken.")]
public List<String> NumberList { get; set; }
In your NumberExists Action take a List of Strings rather than only 1 string. This will let you validate your whole array all at once.
Public ActionResult NumberExists(List<String> NumberList, String UserName){
//Validate list is unique for username
}
UserName Property should be in the same class of the additionalNumbers property:
public class NumbersViewModel
{
public string UserName { get; set; }
[Display(Name = "Additonal Numbers")]
[Remote("NumberExists", "Account", AdditionalFields = "UserName", ErrorMessage = "Serial is already taken.")]
public string additionalNumbers { get; set; }
public List<Numbers> NumberList { get; set; }
}
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. When I try to add a user to the database using Entity Framework Database First I get this exception:
An exception of type 'System.Data.Entity.Validation.DbEntityValidationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
This is the code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(RegisterViewModel account)
{
if (ModelState.IsValid)
{
using (db)
{
bool duplicate = db.Users.Any(a => a.UserName == account.UserName);
if (duplicate)
{
ModelState.AddModelError("", "Username already exists in database!");
}
else
{
db.Users.Add(new StoreFront.Models.User { UserName = account.UserName, Password = account.Password, EmailAddress = account.EmailAddress, IsAdmin = false, DateCreated = DateTime.Now });
db.SaveChanges();
ModelState.Clear();
ModelState.AddModelError("RegisterSuccess", "Successfully registered!");
}
}
}
return View();
}
I have validation in my RegisterViewModel for all fields, and when I debug, IsValid = true, otherwise it wouldn't run anyway. Any help would be greatly appreciated...I have been struggling with this for a while.
P.S. Yes the password is currently being stored as a string, this is just a test project that won't be used in the real world.
EDIT: Added Models:
User Model from database:
public partial class User
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public User()
{
this.Addresses = new HashSet<Address>();
this.Orders = new HashSet<Order>();
this.ShoppingCarts = new HashSet<ShoppingCart>();
}
public int UserID { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string EmailAddress { get; set; }
public Nullable<bool> IsAdmin { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
public string CreatedBy { get; set; }
public Nullable<System.DateTime> DateModified { get; set; }
public string ModifiedBy { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Address> Addresses { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Order> Orders { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ShoppingCart> ShoppingCarts { get; set; }
}
Partial Model to add ConfirmPassword:
namespace StoreFront.Models
{
[MetadataType(typeof(RegisterViewModel))]
public partial class User
{
[DisplayName("Confirm Password")]
[DataType(DataType.Password)]
[Compare("Password", ErrorMessage = "Passwords must match")]
public string ConfirmPassword { get; set; }
}
}
RegisterViewModel:
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; }
public Nullable<bool> IsAdmin { get; set; }
public Nullable<System.DateTime> DateCreated { get; set; }
}
Fix: When I looked up a tutorial about MVC it asked em to create a partial class and a meta class. That was for code first I believe, which basically made it a new field that my database didn't have a spot for, and I am using database first. So I removed the deleted the partial class for User and it stopped making ConfirmPassword an actual field in the database.
Don't know the real works of it, or if what I said makes sense, but I hope this helps someone eventually.
Remove
[RegularExpression(#"^([a-zA-Z0-9_\-\.]+)#([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$",
ErrorMessage = "Please enter a valid email")]
from RegisterViewModel
I have this contact Info model.
namespace School.Models
{
public partial class ContactInfo
{
public ContactInfo()
{
this.Branches = new List<Branch>();
this.People = new List<Person>();
}
public long ID { get; set; }
[Required]
[DataType( System.ComponentModel.DataAnnotations.DataType.PhoneNumber)]
[StringLength(12, MinimumLength=9)]
public string PhoneNumber { get; set; }
[Required]
[DataType(System.ComponentModel.DataAnnotations.DataType.PhoneNumber)]
public string CellNumber { get; set; }
[Required(ErrorMessage="Please enter a valid email like name#domain.com")]
[DataType(System.ComponentModel.DataAnnotations.DataType.EmailAddress, ErrorMessage="xyz#domain.com")]
public string Email { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
public virtual ICollection<Person> People { get; set; }
}
}
I have to set all these fields required , But when i do i get an error that i can't do so. Its working if i remove any one of the required tag but starts giving the error when i make all of them required.
Is there any way that i can set all these fields "Phone Number", "Cell Number", "Email" REQUIRED.
Thanks in advance.
I'm having trouble getting validation to work on my MVC page when using Entity Framework. If someone could point out what I'm doing wrong I would appreciate it. It is definitely seeing the meta data because the labels are working. However, when I hit submit, it just continues on to the next page. Could it have something to do with the fact that I have an instance of a class inside the view model?
Meta Data Class
[MetadataType(typeof(CompanyMetaData))]
public partial class Company
{
}
[MetadataType(typeof(CompanyUserMetaData))]
public partial class CompanyUser
{
}
public class CompanyMetaData
{
[Required(ErrorMessage = "Company Name is required")]
public string Name { get; set; }
[Required(ErrorMessage = "Service Center is required")]
public string ServiceCenterCode { get; set; }
[Required(ErrorMessage = "Account Number is required")]
public string AccountNumber { get; set; }
[Required(ErrorMessage = "Edition is required")]
public string Edition { get; set; }
}
public class CompanyUserMetaData
{
[Required]
[RegularExpression(#"^\w+#[a-zA-Z_]+?\.[a-zA-Z]{2,3}$", ErrorMessage = "Invalid Email Address")]
public string EmailAddress { get; set; }
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; }
[Required(ErrorMessage = "First Name is required")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
[Required(ErrorMessage = "Last Name is required")]
public string LastName { get; set; }
}
View Model
public class CreateCompanyViewModel : ILayoutAwareViewModel
{
public List<AdvisorServiceCenterVW> ServiceCenters { get; set; }
public LayoutViewModel LayoutViewModel { get; set; }
public Company newCompany { get; set; }
public CompanyUser newUser { get; set; }
public List<FuneralHome> newFuneralHomes { get; set; }
}
Markup Sample
<div class="form-group">
<label>#Html.LabelFor(d=>d.newUser.LastName)</label>
<div class="controls">
#Html.TextBoxFor(d => d.newUser.LastName, new { #class = "form-control" })
#Html.ValidationMessageFor(d => d.newUser.LastName)
</div>
</div>
Controller
public ActionResult CreateCompanyLocations(CreateCompanyViewModel incomingModel)
{
var model = (CreateCompanyViewModel)TempData["model"];
LayoutViewModel lvm = _layoutHelper.GetLayoutViewModelData("Configure New Company");
model.LayoutViewModel = lvm;
model.newCompany = incomingModel.newCompany;
model.newUser = incomingModel.newUser;
var fhs = _siteService.GetCustomerLocations(model.newCompany.AccountNumber);
model.newFuneralHomes = new List<FuneralHome>();
foreach (var fh in fhs)
{
model.newFuneralHomes.Add(new FuneralHome()
{
Address = fh.Address,
Name = fh.CustomerName,
City = fh.City,
AccountNumber = fh.AccountNumber,
ServiceCenterCode = fh.ServiceCenterCode,
State = fh.State,
ZipCode = fh.ZipCode,
Phone = fh.Phone,
ContactName = fh.ContactName
});
}
TempData["model"] = model;
return View(model);
}
You need to check ModelState.IsValid in your controller code and branch accordingly. Currently your controller is just processing the model whether it is valid or not. The typical pattern looks something like this:
if(ModelState.IsValid)
{
// Do stuff for when model is valid
}
else
{
// return the view with the invalid model to give the user
// a chance to fix it
return View(model);
}
It wound up having nothing to do with the above answer. I was missing the jquery validation and jquery unobtrusive scripts on my layout page so that is what was causing the validation not to fire. You do NOT need to do anything in the controller for this to work correctly.
I have generic model for contact
public class Contact
{
public string Title { get; set; }
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter LastName")]
public string LastName { get; set; }
[Required(ErrorMessage = "Please enter Email")]
public string Email { get; set; }
public string Phone { get; set; }
}
Now I want to use my contact class in two models but apply the validation only on second?
public class Step1Model{
public Contact Contact{get;set;}
}
public class Step2Model{
[Requried]
public Contact Contact{get;set;}
}
How do I make it work?
I see two options here:
1 - Code to an interface which will require you to create a ContactRequired class and a ContactOptional class based upon the ContactInterface. I believe this will allow you to then have a single StepModel where you would set the StepModel.Contact property to either a new ContactRequired() or a new ContactOption(). Then when the validaiton runs for the StepModel, it will be have based upon the type of class you set for the StepModel.Contact property.
public interface ContactInterface
{
string Title { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
string Email { get; set; }
string Phone { get; set; }
}
public class ContactOptional : ContactInterface
{
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
public class ContactRequired : ContactInterface
{
public string Title { get; set; }
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter LastName")]
public string LastName { get; set; }
[Required(ErrorMessage = "Please enter Email")]
public string Email { get; set; }
public string Phone { get; set; }
}
public class StepModel
{
public ContactInterface Contact { get; set; }
}
Usage:
StepModel smTest = new StepModel();
ContactRequired crContact = new ContactRequired();
ContactOptional coContact = new ContactOptional();
List<ValidationResult> lErrors = new List<ValidationResult>();
smTest.Contact = coContact;
//Validate Option
if (Validator.TryValidateObject(smTest, new ValidationContext(smTest, serviceProvider: null, items: null), lErrors, true))
{
//Code should reach this as the model should be valid;
}
smTest.Contact = crContact;
//Validate Required
if (Validator.TryValidateObject(smTest, new ValidationContext(smTest, serviceProvider: null, items: null), lErrors, true))
{
//Code should not reach this as the model should be invalid;
}
2 - Create a custom required attribute which will look at another property of the Contact model (such as bool UseValidation) to determine if the required validation should even take place or if it should simply return true as the default. I am not initially providing code for this option as you would need a custom attribute for every type of validation attribute in your class. Also, I think option 1 is the better one unless you have a specific reason against it.
I have decided not to have many view models.
Here is my implementation
https://gist.github.com/cpoDesign/bc9c5980a89cfe7b0caf