I'm new to ASP.NET MVC using Entity Framework and I'm trying to create a simple login system. At the moment I have UserProfile model that I wish to model a login form off of.
UserProfile.cs
namespace MyProject.Areas.Admin.Models
{
public class UserProfile {
[Key]
public int UserID { get; set; }
[Required]
[Display(Name = "Username")]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public string Telephone { get; set; }
}
}
As my login form will only require a username and password, is it correct for me to create a separate model (for instance, a LoginModel with just those properties, or should I contine to use the UserProfile model?
It feels better for me to create a separate model to model the login submission, but then I run into the issues such as making them reference the same table?
Thanks
You should have only one Model (Domain model), but different ViewModel class.
The ViewModel will only have the properties (from the Model) needed for a certain View /Action.
To manage mapping between Model and ViewModel(s), you should look at Mapping solutions (like AutoMapper, ValueInjecter...)
It looks you should distinguish view model and domain model. Interestin discussion was here.
Related
so when implementing entity framework code first in mvc, do we separate the view restrictions from view model? this is because for database first the model is generated(so i see the reason to separate it to view model but how about code first?)
The next questions i would ask is it ok to separate view model to another folder? since by default asp.net is MVC there is no view model inside
Model <--- what is this model call? data model? domain model? business model?
public class Student
{
public int ID { get; set; }
[StringLength(250)]
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
}
View Model
public class Student
{
public int ID { get; set; }
[MaxLength(250)]
[Required]
public string LastName { get; set; }
[Required]
public string FirstMidName { get; set; }
[Required]
public DateTime EnrollmentDate { get; set; }
}
Your model that Used in mvc views is viewmodel.
your model that persist in database is domain model.
Your domain model may has some properties that you don't need use it in your client.
Your Service layer must return Dto (data transfer object) to your client and you can map dto to viewmodel .
First Question:
You should use partial class and metadata to seperate , just like below:
[MetadataType(typeof(StudentMD))]
public partial class Student
{
public class StudentMD
{
public int ID { get; set; }
[MaxLength(250)]
[Required]
public string LastName { get; set; }
[Required]
public string FirstMidName { get; set; }
[Required]
public DateTime EnrollmentDate { get; set; }
}
}
Second Question:
It's OK to add a folder name "View Model"
I did it in my project too!
I have read many by many solution but i can't understand deeply about what or when i use View Model?
For example, when i have a Register form for User to register, i want to hava an field Confirm Password, but i don't think should add it into the User entity. So i have this ViewModel:
public class RegisterViewModel
{
public User User { get; set; }
public IEnumerable<SelectListItem> City { get; set; }
public IEnumerable<SelectListItem> Ward { get; set; }
[Required(ErrorMessage = "Bạn chưa nhập lại mật khẩu.")]
[StringLength(100, ErrorMessage = "Mật khẩu phải có ít nhất {2} ký tự.", MinimumLength = 6)]
[DataType(DataType.Password)]
[System.Web.Mvc.Compare("User.Password", ErrorMessage = "Mật khẩu không khớp.")]
public string ConfimPass { get; set; }
}
So after read this link How to properly implement "Confirm Password" in ASP.NET MVC 3? . I don't know why they should replace the Password field which is already in User entity. I'm using unobstrusive client validation so it does work if i use this Model View. In my View, i must use m=> m.User.Username but not m=>m.Username, etc... Because of this, my validation such as compare password, or just remote validation not work well with the name in my View like m=>m.User.Username. What is wrong with my structure or my Model View in my thinking?
There is no single rule and you need to stay pragmatic, having said that ViewModel and a Model (or Domain Model) are 2 different things. No you don't pollute your entities by placing properties that don't belong to them. The idea is that your UI should be interchangeable and your domain should not in any way depend on it. The dependencies should be inverted. Maybe tomorrow you'd switch (or extend) your UI layer to WPF (for example) ? Where your current ViewModels (with their attributes) wouldn't make much sense.
In your case, yes you should be creating a view model and keep everything relevant to the view in them, after which you map/pass values back to your domain model.
I hope I'm making sense, let me know if you need clarifications.
In your case I'd probably create a flattened RegisterViewModel that would include only the information needed to register a user, for example:
public class RegisterViewModel
{
[Required]
public string DisplayName { get; set; }
[Required]
public string FirstName { get; set; }
// etc ...
public IEnumerable<SelectListItem> City { get; set; }
public IEnumerable<SelectListItem> Ward { get; set; }
[Required(ErrorMessage = "Bạn chưa nhập lại mật khẩu.")]
[StringLength(100, ErrorMessage = "Mật khẩu phải có ít nhất {2} ký tự.", MinimumLength = 6)]
[DataType(DataType.Password)]
[System.Web.Mvc.Compare("User.Password", ErrorMessage = "Mật khẩu không khớp.")]
public string ConfimPass { get; set; }
}
I am developing a ASP.NET MVC 3 application, i am using entity framework code first in order to create the classes of my app, and i also have a repository in order to perform the operations on it, keeping clean the DBContext and the DBEntities definitions.
My doubt is about the render of the views and the way where a edit model is saved.
If I have this entity that represent a user stored in my DB:
//Entity:
public class User
{
[Key]
public int IdUser { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
And i want to show a View with the FirstName, LastName, Email and NewPassword, ConfirmPasword and CurrentPassword, in order to let the user change his data, typing the CurrentPassword to confirm the changes, so my doubt is, fieds like ConfirmPasword and CurrentPassword aren´t in my entity so i need to create a new model for this View and the copy the information that i want from my new Model to my database entity in order to save it? Like:
public class UpdateUserModel
{
[Required]
[Display(Name = "Name")]
public string FirstName{ get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName{ get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Not valid email")]
public string Email { get; set; }
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPasword{ get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm the New Pasword")]
[Compare("NewPasword", ErrorMessage = "Password doesn´t mach.")]
public string ConfirmPasword{ get; set; }
[Required(ErrorMessage = "Need to specify the current password to save changes")]
[DataType(DataType.Password)]
[Display(Name = "Current Password")]
public string CurrentPassword { get; set; }
}
and in the controller i made:
public ActionResult UpdateUser(UpdateUserModel model)
{
User u = (User)Membership.GetUser();
u.FirstName = model.FirstName;
u.LastName = model.LastName;
u.Email = model.Email;
if (!String.IsNullOrEmpty(model.NewPassword))
{
u.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(model.NewPassword.Trim(), "md5");
}
repository.UpdateUser(u);
return View();
}
There are any way of doing this having a controller like:
public ActionResult UpdateUser(User u)
{
repository.UpdateUser(u);
return View();
}
Because if i have that, how i can add the field like, ConfirmPassword or CurrentPassword in order to made the validation for this specific View.
If I were you, I wouldn't use domain model in my presentation layer. I would create a view model (another class) which will be very similar to my domain model. I would then use auto-mapping tool to map from my domain model to the view model.
This is a very common scenario, so if you Google for "view and domain" models you should find everything you need.
public class User {
[Key]
public int IdUser { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class UpdateUserViewModel {
// Original fields
public string Password { get; set; }
public string PasswordConfirmation { get; set;
}
You could then configure auto-mapper to remove your boiler plate code:
public ActionResult ShowUser()
{
var domainModel = new User(); // I'm assuming that properties are set somewhere
var viewModel = new UserViewModel();
Autommaper.Map(domainModel, viewModel);
return View(viewModel);
}
This is very rough, but hopefully you get an idea.
Update 1: **
As i understood is better to create a new model for each view and then map it into the entity
It's not just better, it provides better separation of concerns, makes your code easily testable. Just by looking at the name of the class, I can see its purpose UpdateUserViewModel, RegisterUserViewModel etc).
Original fields, in this class is supposed to be the Metadata with the validation and that stuff isn't?
By original fields I mean:
public class UserViewModel{
public string UserName { get; set; }
public string FirstName { get; set; }
}
These fields are already in your User class, so I saved my time by not typing them in again.
This will be change my model from MVC to MVVM or not beacuse i still have a controller?
I believe what I've suggested is still an MVC pattern, rather than MVVM.
About the Automaper, are you using github.com/AutoMapper/AutoMapper?
Automapper is something that I have used. There are few tools out there and they do pretty much the same thing. Try out few and find one that suits your requirements the most.
Good luck.
Usually I use areas for different parts of my project, as an aside of where to put this extra code.
Pretty much you are going to add to your model folder a viewmodel.cs class. Inside this class will hold your definitions for how the data will be modelled in the view. These viewmodels will reflect the parts of the entity you wish the user to interact with. The interaction will be done in the controllers via [HttpGet] where you pass in the view model to be interacted with, and [HttpPost] where you send the model back and then map it to an entity.
ViewModels.cs:
public class UserViewModel
{
public string UserName { get; set; }
}
SomeController:
public ActionResult getView()
{
var uvm = new UserViewModel();
return View(uvm);
}
View getView.cshtml:
#model project.namespace.UserViewModel
#using (Html.BeginForm())
{
#Html.EditorFor(m => m.UserName)
<input type="submit" value="New User Name" />
}
Back in controller:
[HttpPost]
public ActionResult getView(UserViewModel model)
{
var entity = new ActualEntity();
entity.username = model.UserName;
//more mapping
//commit changes somewhere
return RedirectToAction("getView");
}
I have a UserFormModel which contains a UserModel which has a set of properties with the [Required] attribute set. I have read that MVC 3 out of the box will validate models within models by default. However when I submit an empty form in my view passing back a UserFormModel containing an empty UserModel the ModelState.IsValid is always true.
I have tried sending just the UserModel back to my controller and that validates ok. It just seem to be when I am working with complex models that it does not validate.
I have also tried it with the [Required] attribute on the User property within the UserFormModel (which I believe is not required for default behaviour to work) but still no validation takes place.
Any ideas on this one would be much appreciated.
public class UserFormModel
{
public UserModel User;
public IEnumerable<SelectListItem> Roles { get; set; }
}
public class UserModel : ModelBase
{
[Required]
public string UserName { get; set; }
public string Title { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
[HttpPost]
public ActionResult Create(UserFormModel userFormModel)
{
if (ModelState.IsValid)
{
// Do Something
}
}
You should use properties not fields. So instead of:
public UserModel User;
you should have:
public UserModel User { get; set; }
The reason for this is that the default model binder works only with properties.
I believe that validation only goes one model property deep in the model. For example if you have the following model
public class Product
{
public int ProductId { get; set; }
[Required]
public int ProductName { get; set; }
[Required]
public decimal Price { get; set; }
}
public class ProductViewModel
{
[Required]
public Product Product { get; set; }
}
The validation against the product object in the view model will work, the validation against the product class will not with one caveat. If the Product class is a POCO class used in the entity framework code first method, the validation will work against the database. Validation against a view model will only work one deep in my experience.
I have a Person model and a student model. The student model has 2 FKs of PersonIDs; one for student and the other for parent.
My view looks like this:
#Html.EditorFor(m => m.student.Person.FirstName)
#Html.EditorFor(m => m.student.Person.DOB)
#Html.EditorFor(m => m.student.Father.FirstName)
The models would look like this:
public partial class Person
{
public int PersonID { get; set; }
[Required]
[PlaceHolder("First Name")]
public string FirstName { get; set; }
[PlaceHolder("Birth Date")]
public Nullable<System.DateTime> DOB { get; set; }
}
public partial class Student
{
public int Student_PersonID { get; set; }
public int Parent_PersonID { get; set; }
}
I want the DOB to be required field for the student but not for the parent. If I add [Required] attribute to the DOB element, then it requires it for both. Is there a way I can set a require a field on the view? or is there a way in the model or using validation attribute to do this?
fyi... i am using EF database first approach
thanks
I would suggest having the view model match the fields that are displayed in the view. If later a field is to be removed from the view, then it will also be removed from the domain model.
In this case, if your view is to display the following fields:
StudentFirstName
StudentDOB
ParentFirstName
ParentDOB
Then I would suggest having the following view:
public class PersonViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Or if instead you have 2 seperate views displaying:
StudentFirstName
StudentDOB
AND displaying:
ParentFirstName
ParentDOB
Then I would suggest having 2 seperate view models:
public class StudentViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
}
public class ParentViewModel
{
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Using the view models in this way will allow you to use the [Required] data annotations for the fields that require them rather than trying to create a workaround. Note that the view models are not to be confused with the domain models and therefore this data would then need to be mapped to the domain model.
Hope this helps.
If your application is a simple application you may not need to create a seperate business logic layer and most books only present MVC with simple models which may be fine. However, if you search around you will find other examples where developers recommend having a view model seperate from a business model such as this
I would also recommend reading Wrox Professional Enterprise .Net 2009 where chapters 7 & 8 give great examples of the business layer with discussions of the Transaction Script pattern, Active Record pattern and Domain Model pattern.
One way is to make a PersonRequired class that inherits from Person. Add a metadata class to PersonRequired so you have PersonRequiredMetaData and in that specific that the inherited DOB field is required. You would need to manually copy the values between the Person and PersonRequired classes or use AutoMapper. I hope there is a better answer than this!
Another option is to use FluentValidation that would let you do the validation separate from the model (doesn't use data annotations). I wonder if some people are using data annotations for database requirements and fluent validation for programmatic requirements.