MVC 4 view model validation attribute - string length - error - validation

I have this property on the MVC5 viewmodel with the StringLength validation attribute:
[Required]
[StringLength(4, MinimumLength = 4, ErrorMessage = "The postcodes must be 4 characters long.")]
[Display(Name = "Postcode (four digits)")]
public int Postcode { get; set; }
The client-side validation works, but when I execute the action by submitting the form I am getting this error:
Unable to cast object of type 'System.Int32' to type 'System.String'.
I know it is the attribute that's causing this because everything works when I comment out the [StringLength] attribute.
I suspect that this is to do with the fact that the property type is int. But how to specify string length validation of an integer property? Is putting string type in ViewModel and then parsing it to int in the controller the best solution or is there an attribute for that? At attribute-driven solution would be nice.
EDIT: I tried [DataType(DataType.PostalCode)] but it didn't work.
Thanks.

DataType attributes can't be used to validate user input. They only provide hints for rendering values using templated helpers.
The range is a perfect validation for int's.
[Required]
[Range(1000,9999, ErrorMessage="The postcodes must be 4 characters long.")]
[Display(Name = "Postcode (four digits)")]
public int Postcode { get; set; }

int uses range, strings use string length, you cannot convert string length to int. [DataType(DataType.PostalCode)] will only work with a string. for postal code you can do a few things.
I suggest to make it a string.
i would make it a string with RegularExpression:
[Required(ErrorMessage = "Postal Code is Required")]
[DataType(DataType.PostalCode)]
[RegularExpression(#"^\d{5}(-\d{4})?$", ErrorMessage = "Postal Code Invalid.")]
[Display(Name = "Postcode (four digits)")]
public string Postcode { get; set; }

Related

MVC Model doesn't catch all model errors

This is part of a an MVC model class:
[Required]
[StringLength(2, ErrorMessage = "Two characters.")]
public string StateProvince { get; set; }
If I submit my form with a blank StateProvince, I will get an error message. If I submit it with one character in StateProvince, no problem. Here's how I get back error messages:
if (!ModelState.IsValid)
{
MyMessage ErrMsg = new MyMessage();
ErrMsg.StatusCode = 101;
ErrMsg.StatusMsg = string.Join("; ", ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage));
return "[" + JsonConvert.SerializeObject(ErrMsg) + "]";
}
MyMessage is structured like so:
public class MyMessage
{
public int StatusCode { get; set; }
public string StatusMsg { get; set; }
}
Am I right to conclude that the StringLength decoration only serves to create client-side validation in the html input field?
Since I'm coding the HTML myself and not using Asp.Net to generate it, then should I just omit the StringLength decoration on the model field and instead write server-side validation code for that in the controller? (And that violates MVC, right?)
Oops! Sorry! StringLength was working. It only prevents excess characters, not minimum number of characters. I know there's code for enforcing an exact length; I've seen it before and will look it up.

MVC dataannotations decimal datatype validation

My application is made on ASP.NET MVC4.And i am using MVC dataannotations validations in my viewmodel classes.
I have one decimal type column.And i am using below regular expression to validate it.
[RegularExpression(#"^\$?([0-9]{1,3},([0-9]{3},)*[0-9]{3}|[0-9]+)(.[0-9][0-9])?$",ErrorMessage = "Amount is invalid.")]
public decimal Amount { get; set; }
And with the help of above regular expression its working well.
But I want to add one more condition there.Which is if someone enters number like:
12.
445.
Then it should accept it and also should adds .00 means (12.00,445.00) automatically.
FYI, I have changed the above regular expression like this:
[RegularExpression(#"^\$?([0-9]{1,3},([0-9]{3},)*[0-9]{3}|[0-9]+)(.[0-9][0-9]|.)?$",ErrorMessage = "Amount is invalid.")]
And by this its accepting the numbers like:
12.
445.
But due to MVC datatype decimal filed its giving the another validation message..
Can anyone suggest me how i can manage that?
I'd offer using shadow field:
class myModel
{
...
public decimal Amount { get; private set; }
[RegularExpression(#"^\$?([0-9]{1,3},([0-9]{3},)*[0-9]{3}|[0-9]+)(.[0-9][0-9])?$",ErrorMessage = "Amount is invalid.")]
public string AmountStringed //use this field on your form input
{
get { return Amount.ToString(); }
set { Amount = decimal.parse(value); } //assign Amount
}
}
So you don't have to do any hacks with either client or server side valiedations

Custom error message not working for DateTime validation in asp net mvc 3

I have a ViewModel with a String property and the following Data Annotation :
Edit to work with string
[DataType(DataType.Date, ErrorMessage="Not Working !!!")]
public String StringBirthDate1 { get; set; }
That's my view
#Html.EditorFor(model => model.StringBirthDate1 )
#Html.ValidationMessageFor(model => model.StringBirthDate1)
If I run my application and put an invalid Date like '---' or 29.02.1900 I don't get any validation error !
Ok I've given up trying to use built-in MVC tools for data validation !
I did a custom Validation Attribute :
public class ValidDateStringAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
DateTime dtout;
if (DateTime.TryParse(value.ToString(), out dtout ))
{
return true;
}
return false;
}
}
Here is my View Model decorated with the custom attribute :
[ValidDateString(ErrorMessage="Invalid date format")]
public String BirthDate1 { get; set; }
Works like a charm :-)
It seems to me, that [DataType(DataType.Date, ErrorMessage="Not Working !!!")] working when it attached to string property. Try to use:
[DataType(DataType.Date, ErrorMessage="Not Working !!!")]
puplic string StringBirthDate1{get;set;}
public DateTime BirthDate1
{
get{return DateTime.Parse(StringBirthDate1);}
set{StringBirthDate1 = value.ToString();}
}
I didn't like any of the solutions I found so I kept poking at possibilities until I came up with one I do like. I added a regular expression validator utilizing the regular expression from this article: http://answers.oreilly.com/topic/226-how-to-validate-traditional-date-formats-with-regular-expressions/
[Required(ErrorMessage = "Birthdate is required. [MM/DD/YYYY]")]
[RegularExpression(#"^([1-9]|0[1-9]|1[0-2])[- / .]([1-9]|0[1-9]|1[0-9]|2[0-9]|3[0-1])[- / .](1[9][0-9][0-9]|2[0][0-9][0-9])$", ErrorMessage = "Birthdate must be in MM/DD/YYYY format.")]
public Nullable<DateTime> Birthdate { get; set; }
The result is, if the field is blank I get the required error message and if anything is in the field, but it is not a valid date, I get the regular expression message.
I might add that it seems very silly that [DataType] doesn't accept an error message. I tried exactly like the original author of this thread. That would have been logical and intuitive.

MVC 3 validation: how to override DataAnnotations attribute in specific use cases?

In an ASP.NET MVC3 app I have a model that represents a user address with the typical Name, StreetAddress 1 & 2, City, Region, PostalCode and Country properties. The model currently has DataAnnotation attributes that apply to US addresses. I now need to support international addresses that will have different validation and messages depending on the Country value that is included in the model. How do I define and override the existing US DataAnnotation attribute values when the country is something like India or Japan instead of US?
For example the existing PostalCode property is defined as this:
private string _postalCode;
[StringLength(10, ErrorMessage = "Zip Code maximum length 10 characters")]
[Display(Name = "Zip Code")]
[Required(ErrorMessage = "Zip Code is required")]
[RegularExpression(#"^\d{5}(-\d{4})?$", ErrorMessage = "Invalid Zip Code")]
public string PostalCode
{
get { return _postalCode; }
set
{
if (_postalCode != value)
{
_postalCode = value;
}
}
}
I know if I had a specific India address model then the postal code would look something like this:
private string _postalCode;
[StringLength(6, ErrorMessage = "Postal Code maximum length 6 characters")]
[Display(Name = "Postal Code")]
[Required(ErrorMessage = "Postal Code is required")]
[RegularExpression(#"^([0-9]{6})$", ErrorMessage = "Invalid Postal Code")]
public string PostalCode
{
get { return _postalCode; }
set
{
if (_postalCode != value)
{
_postalCode = value;
}
}
}
How can I implement the proper client and server side validations using this model when a user selects a particular country?
I'm expecting to either do an ajax call to retrieve an updated partial view when the country is changed, or send enough data to the client so I can adjust the client side prompts and validation by modifying the appropriate attributes on the input elements and resetting validation, but how can I get the server side model to validate properly when issuing a Model.IsValid() call?
With complex validations, I find it easiest to imeplement IValidatableObject interface
IEnumerable<ValidationResult> Validate(
ValidationContext validationContext
)
Basically something like this
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
MyAddress model = validationContext.ObjectInstance as MyAddress;
if (model.Country == "India")
{
// validate as india
}
}
This seemlessly integrates with default validation system, so you won't need any additional configurations. But to note, this is only the server side validation.

one property from my ViewModel will not populate ModelMetadata

I'm experiencing very odd behavior in the way an ASP.NET MVC3 view model is emitted -- for one field, ModelMetadata is not propagated. I'm using the templated helpers after Brad Wilson, though updated for Razor. Here's my view model:
public class FamilyBaseViewModel : ViewModelBase
{
[Display(Order = 10)]
public string FamilyName { get; set; }
[Display(Order = 30)]
[StringLength(50, ErrorMessage = "Street name can only be 50 characters long.")]
public string Street { get; set; }
}
public class FamilyPrivateViewModel : FamilyBaseViewModel
{
[Display(Name = "Date Started", Order = 20)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
[DataType(DataType.Date)]
public DateTime? DateStarted { get; set; }
}
The object.cshtml template runs through the properties and uses Html.Display to show them:
// object.cshtml
<ol>
#foreach (var prop in
ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay
&& !ViewData.TemplateInfo.Visited(pm)
&& pm.ModelType != typeof(System.Data.EntityState)))
{
<li>
#Html.Display(prop.PropertyName)
</li>
}
</ol>
In the above scenario, all three fields have the right descriptors in the object.cshtml call (prop.DisplayName, prop.TemplateHint), but when the first property -- FamilyName -- is passed to String.cshtml, the ViewData.ModelMetadata is not populated at all. As a result, the template can't display a label (except "String"), nor assign the ID of the control, etc.
Street and DateStarted are emitted normally, with the ID and all. So I'm completely at a loss as to why the one property would fail to set the ViewData properties -- nor do I know how to step through past the Html.Display call to see what might be happening.
Any ideas for a next place to look?
So the problem was in the controller action, which for unrelated reasons used "FamilyName" for a ViewData value:
ViewBag.FamilyName = familyName;
And this caused all heck to break loose in the mapping of model fields with the same name -- that is, ModelMetadata will not propagate. So, the lesson is: don't give ViewData dictionary items keys with the same name as a field in your view model.

Resources