MongoDB C# - Hide property from serializer - asp.net-mvc

This is what my user model looks like:
namespace Api.Models
{
public class User
{
[BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
[BsonRequired]
public string Id { get; set; }
[Required(ErrorMessage = "Username is required.")]
[StringLength(20, MinimumLength=3, ErrorMessage="Username must be between 3 and 20 characters.")]
[BsonRequired]
public string Username { get; set; }
[Required(ErrorMessage="Email is required.")]
[EmailAddress(ErrorMessage="Valid email required.")]
[BsonRequired]
public string Email { get; set; }
[Required(ErrorMessage = "Password is required.")]
[StringLength(50, MinimumLength=8, ErrorMessage="Password must be between 8 and 50 characters.")]
[BsonRequired]
public string Password { get; set; }
[BsonRequired]
public string Salt { get; set; }
}
}
I want to write, and require, all of the properties into the MongoDB Database. What I don't want to do, is expose the Password and Salt properties when I send this through the request.
Is there any sort of data attribute that I can set that will write it, but not expose it when displayed to any API user?

The correct approach is to use view models. Don't pass your domain entities to the views. Design view models that meet the specific requirements of your views. So for example design a view model that doesn't have the Password and Salt properties because that's what this view needs. Then in order to ease the mapping between your domain models and view models you could use AutoMapper.
If you don't want to follow good practices with view models you still have the possibility to clutter your POST actions with the Bind attribute and decide which properties you want to be included/excluded from model binding. For example:
[HttpPost]
public ActionResult SomeAction([Bind(Exclude="Password,Salt")]User user)
{
// at this stage the Password and Salt properties will always be null =>
// they will never be bound from the request even if the user attempts to
// forge an HTTP request and include them
...
}

Related

Prevent to use default model data annotations in ViewModel

I started working on my first serious MVC project for school unfortunately without defining the data annotations to the model first (so did not set "required" annotation, limit to size of attribute names etc.). I work with a viewmodel, and after adding the annotations the model is causing my ViewModel state to get invalid when posting the form.
It seems like it's the email required that is causing the issue. It is not used on viewmodel and in the form and it seems the viewmodel expects it will get it. Is there a way the form to stop demanding this field by setting some limitation in viewmodel (or controller). I would really prefer not to change the structure of the application (if I start from the scratch I would probably do this a bit different, but not much time is left to finalize the project)
Customer (Model)
public Class Customer(){
public int Id { get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(25, ErrorMessage = "Message"]
public string Name { get; set; }
public string Logo { get; set; }
//[Required(ErrorMessage = "Email required")]
//[Display(Name = "E-mail")]
//[RegularExpression(xxxx, ErrorMessage = "not correct")]
public string Email { get; set; }
public int UserId { get; set; }
}
ViewModel
public class CustomerEditViewModel
{
public Customer Customer { get; set; }
[FileTypes("jpg,jpeg,png")]
[FileSize(1024 * 1024, ErrorMessage = "Max x bytes")]
public HttpPostedFileBase File { get; set; }
}
You can remove errors from the modelstate in your controller, e.g.
this.ModelState[key].Errors.Clear();
where key is the bit to be cleared, so if it's email it's most likely -
this.ModelState["Customer.Email"].Errors.Clear();

Should I have each ViewModel for each entity in my ASP MVC project?

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; }
}

Using a model for multiple purposes

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.

Optional Validation for Change Password in ASP.NET MVC

I have the following model
public AccountInfo {
// loads of other property here as well.
public string Password { get; set; }
public string NewPassword { get; set; }
[Compare("NewPassword", ErrorMessage = "New Passwords dont match.")]
public string ConfirmNewPassword { get; set; }
}
I am using data annotations to display client side validation message.
Now I am working on the change user profile details page.
What I am required to do is, Along with the other details such as email, full name, address etc, I have to show 3 fields namely
Current password
New password
Confirm New password
Now the scene is that these are optional fields and user may not fill it. But when he does, I want to make sure all the 3 fields are filled., if not I want to show some validation error using data annotation.
Any Thoughts ?
There isn't any built in data annotation for this. You could create your custom attribute to do the validation, but it's not easy. As such, I would suggest you to use Jquery Validation / Javascript to handle this.
Basically you would want to override the submit event and do your own validation logic in there. You code will be similar to this:
function SubmitToServer() {
if ($('#Password').length == 0 || ($('#Password').length > 0 && $('#NewPassword ').length > 1 && $(formId).valid()) {
$(formId).submit();
}
}
You can use [Required] to tell the RAZOR that these are must or mandatory like that..
[Required]
public string Password { get; set; }
[Required]
public string NewPassword { get; set; }
[Required]
[Compare("NewPassword", ErrorMessage = "New Passwords dont match.")]
public string ConfirmNewPassword { get; set; }
If you want to Provide range of value means use this one - [Range(1, 100)]
If you want to use password lenght means use this one - [StringLength(5)]

Model does not apply DataType.Password

Instead of using the object directly, on a simple Razor View I have a form using as it+s model a decorator object.
public class GlobalAccount
{
public GlobalAccount()
{
this.TestService = new TestServiceModel();
}
public TestServiceModel TestService { get; set; }
}
beeing TestServiceModel represented as
public class TestServiceModel
{
[Required]
[Display(Name = "Endpoint (url of your service like http://mydomain/remote/)")]
public string Endpoint { get; set; }
[Required]
[Display(Name = "System username")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "System password")]
public string Password { get; set; }
}
Note the Password property decorated with DataType.Password
and in a Partial Razor view I have a call to that object
#model OnlineServices.Administration.Models.GlobalAccount
...
#Html.TextBoxFor(model => model.TestService.Password, new { size = "30" })
problem is that, in the html I get type="text" instead of text="password"
You can see in this image the entire flow:
What am I missing here?
You should use Html.Password, or even better use Html.EditorFor which will read the DataType.Password and output a password type input for you.
The Html.TextBoxFor is just text based input, not as password based one.
Further to Kieron's answer, in MVC3 it is actually NOT better to use Html.EditorFor for the Password inputs, as for some reason, if the server returns the page (say the username password combo is incorrect) then with EditorFor, the password is transmitted back to the page (and a view source the password is visible)
When using the Html.PasswordFor the password is not transmitted back to the client.

Resources