Int or Number DataType for DataAnnotation validation attribute
asp.net Mvcasp.net Mvc-3Data Annotationsasp.net Mvc Problem Overview
On my MVC3 project, I store score prediction for football/soccer/hockey/... sport game. So one of properties of my prediction class looks like this:
[Range(0, 15, ErrorMessage = "Can only be between 0 .. 15")]
[StringLength(2, ErrorMessage = "Max 2 digits")]
[Remote("PredictionOK", "Predict", ErrorMessage = "Prediction can only be a number in range 0 .. 15")]
public int? HomeTeamPrediction { get; set; }
Now, I need also change error message for a data type, int
in my case. There is some default one used - "The field HomeTeamPrediction must be a number.". Need to find a way how to change this error message. This validation message also seem to take prediction for Remote validation one.
I've tried [DataType]
attribute but this does not seem to be plain number in system.componentmodel.dataannotations.datatype
enumeration.
asp.net Mvc Solutions
Solution 1 - asp.net Mvc
For any number validation you have to use different different range validation as per your requirements :
For Integer
[Range(0, int.MaxValue, ErrorMessage = "Please enter valid integer Number")]
for float
[Range(0, float.MaxValue, ErrorMessage = "Please enter valid float Number")]
for double
[Range(0, double.MaxValue, ErrorMessage = "Please enter valid doubleNumber")]
Solution 2 - asp.net Mvc
Try one of these regular expressions:
// for numbers that need to start with a zero
[RegularExpression("([0-9]+)")]
// for numbers that begin from 1
[RegularExpression("([1-9][0-9]*)")]
hope it helps :D
Solution 3 - asp.net Mvc
Use regex in data annotation
[RegularExpression("([0-9]+)", ErrorMessage = "Please enter valid Number")]
public int MaxJsonLength { get; set; }
Solution 4 - asp.net Mvc
public class IsNumericAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
decimal val;
var isNumeric = decimal.TryParse(value.ToString(), out val);
if (!isNumeric)
{
return new ValidationResult("Must be numeric");
}
}
return ValidationResult.Success;
}
}
Solution 5 - asp.net Mvc
Try this attribute :
public class NumericAttribute : ValidationAttribute, IClientValidatable {
public override bool IsValid(object value) {
return value.ToString().All(c => (c >= '0' && c <= '9') || c == '-' || c == ' ');
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.DisplayName),
ValidationType = "numeric"
};
yield return rule;
}
}
And also you must register the attribute in the validator plugin:
if($.validator){
$.validator.unobtrusive.adapters.add(
'numeric', [], function (options) {
options.rules['numeric'] = options.params;
options.messages['numeric'] = options.message;
}
);
}
Solution 6 - asp.net Mvc
I was able to bypass all the framework messages by making the property a string in my view model.
[Range(0, 15, ErrorMessage = "Can only be between 0 .. 15")]
[StringLength(2, ErrorMessage = "Max 2 digits")]
[Remote("PredictionOK", "Predict", ErrorMessage = "Prediction can only be a number in range 0 .. 15")]
public string HomeTeamPrediction { get; set; }
Then I need to do some conversion in my get method:
viewModel.HomeTeamPrediction = databaseModel.HomeTeamPrediction.ToString();
and post method:
databaseModel.HomeTeamPrediction = int.Parse(viewModel.HomeTeamPrediction);
This works best when using the range attribute, otherwise some additional validation would be needed to make sure the value is a number.
You can also specify the type of number by changing the numbers in the range to the correct type:
[Range(0, 10000000F, ErrorMessageResourceType = typeof(GauErrorMessages), ErrorMessageResourceName = nameof(GauErrorMessages.MoneyRange))]
Solution 7 - asp.net Mvc
almost a decade passed but the issue still valid with Asp.Net Core 2.2 as well.
I managed it by adding data-val-number
to the input field the use localization on the message:
<input asp-for="Age" data-val-number="@_localize["Please enter a valid number."]"/>
Solution 8 - asp.net Mvc
ASP.NET Core 3.1
This is my implementation of the feature, it works on server side as well as with jquery validation unobtrusive with a custom error message just like any other attribute:
The attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeIntegerAttribute : ValidationAttribute, IClientModelValidator
{
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
var errorMsg = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
MergeAttribute(context.Attributes, "data-val-mustbeinteger", errorMsg);
}
public override bool IsValid(object value)
{
return int.TryParse(value?.ToString() ?? "", out int newVal);
}
private bool MergeAttribute(
IDictionary<string, string> attributes,
string key,
string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
Client side logic:
$.validator.addMethod("mustbeinteger",
function (value, element, parameters) {
return !isNaN(parseInt(value)) && isFinite(value);
});
$.validator.unobtrusive.adapters.add("mustbeinteger", [], function (options) {
options.rules.mustbeinteger = {};
options.messages["mustbeinteger"] = options.message;
});
And finally the Usage:
[MustBeInteger(ErrorMessage = "You must provide a valid number")]
public int SomeNumber { get; set; }
Solution 9 - asp.net Mvc
You can write a custom validation attribute:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class Numeric : ValidationAttribute
{
public Numeric(string errorMessage) : base(errorMessage)
{
}
/// <summary>
/// Check if given value is numeric
/// </summary>
/// <param name="value">The input value</param>
/// <returns>True if value is numeric</returns>
public override bool IsValid(object value)
{
return decimal.TryParse(value?.ToString(), out _);
}
}
On your property you can then use the following annotation:
[Numeric("Please fill in a valid number.")]
public int NumberOfBooks { get; set; }