Optional Validation for Change Password in ASP.NET MVC - 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)]

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();

MVC.net Hiding Fields within a model

So I am creating a an API with ASP.net MVC Web API. I currently have a model which contains the fields for a user in the database. I have a password field on this model. See below for an example.
public class Account
{
[Key]
public Guid UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
I return this model using JSON when a controller method is called over HTTP. This works fine.
My question is, how do I stop the password field being returned alongside with it? Without removing the field altogether.
My initial idea is to create another model class which I use to return the data without the password field, but I'd rather not repeat myself for the sake of one field.
Any suggestions?
You should be able to mark these fields with
[JsonIgnore]
[XmlIgnore]
public string Password { get; set; }
Preventing these fields to be used in either JSON or XML requests.

MongoDB C# - Hide property from serializer

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

MVC validation for unique

Hi I have an MVC app that I used to insert update invoices:
public class Invoice : IEntity, IValidatableObject
{
public virtual int InvoiceId { get; set; }
[Required(ErrorMessage = "Invoice Number is a required field.")]
[Column(TypeName = "varchar")]
[StringLength(20)]
[Display(Name = "Invoice Number:")]
public virtual string InvoiceNumber { get; set; }
[Required(ErrorMessage = "Organisation is a required field.")]
[Display(Name = "Organisation:")]
public int OrganisationId { get; set; }
...
}
The problem is I have a requirement "The combination of organisation and invoice number must be unique.
So this has been set up by the DBA in the database. So if I try to do this it will return an exception.
Is there a way instead of displaying the exception to catch it and add a custom error message to the validation summary?
You could catch the exception and add the error to the model state so that your client code handles all errors the same way. Something like:
ModelState.AddModelError("InvoiceNumber", "The combination of organisation and invoice number must be unique.");
you can achieve this by putting remote attribute on both properties and in AdditionalField parameter you pass the name of other property like
[Remote("IsUnique","home",AdditionalFields = "OrganisationID",ErrorMessage = "abc")]
virtual string InvoiceNumber { get; set; }
[Required(ErrorMessage = "Organisation is a required field.")]
[Display(Name = "Organisation:")]
[Remote("IsUnique","home",AdditionalFields = "InvoiceNumber",ErrorMessage = "abc")]
public int OrganisationId { get; set; }
and you can write InUnique method in home controller (for instance) like
public JsonResult IsUnique(string InvoiceNumber, int? OrganisationID)
{
if(InvoiceNumber == null || !Organisation.HasValue)
{
return Json({valid = true});//null check is not job of this attribute
}
else
{
bool result = CheckDbForUniqueness(InvoiceNumber, OrganisationID.Value);
return Json({valid = result});
}
}
This method will be invoked when you change value of either inputs on the form and take the other value as parameter. if either value is null it would return true and null checking will be handled by Required attributes.
Without getting fancy...you could catch it in the controller, then display the message in the view via a member of the model or ViewBag/ViewData.
You can also write a custom validator that checks this for you (even with some client-side validation as well). I wrote one that checked a database for whether a username existed or not, a similar check could be done for this, without relying on exceptions (although you still would want to handle it I wouldn't recommend using exceptions for a normal course of action).

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