DataAnnotations localization message issue for RegEx validation - asp.net-mvc

I have a problem with the validation message for Regular expression. Localised messages appear everywhere except for one field below:
[LocalizedDisplayName("LblWordCount", NameResourceType = typeof(ValidationMessages.Messages))]
[Required(ErrorMessageResourceName = "ErrorFieldRequired", ErrorMessageResourceType = typeof(ValidationMessages.Messages))]
[RegularExpression(#"^[0-9]+$", ErrorMessage = "", ErrorMessageResourceName = "ErrorDigitsOnly", ErrorMessageResourceType = typeof(ValidationMessages.Messages))]
public Int32 WordCount { get; set; }
It doesn't matter what I put in the resx file for "ErrorDigitsOnly" - the default message always kicks in: "The value 'zxzza1' is not valid for Word Count." For instance - message for the [Required] appears correctly.
Any suggestions for that?
Cheers,
303
I have checked the code for spelling mistakes but couldn't find any.

I actually ran across a similar situation myself.
Have you tried setting the wordcount validation in another class instead of using the regex pattern in the DataAnnotation Attribute?
For example -
public class EmailAttribute: RegularExpressionAttribute
{
public EmailAttribute() : base(#"[^#\.]+(\.[^#\.]+)*#[^#\.]+(\.[^#\.]+)?(\.[^#\.]{2,})")
{
}
public override string FormatErrorMessage(string name)
{
return Resources.Resources.emailValidation;
}
}
You can then use the attribute like so -
[CustomRequired]
[Email]
public string Email { get; set; }
The advantages of using it this way means that you get strong typing on your resources and it also allows you to write neater validation classes.
Hope it helps!

Related

ASP.NET MVC optional field being treated as required

I have this field that for some reason when I click on submit, gets a validation message that the field is required.
[DisplayName("Total Budget:")]
public double Budget { get; set; }
#Html.EditorFor(model => model.account.Budget)
#Html.ValidationMessageFor(model => model.account.Budget)
public class Account
{
[DisplayName("Total Budget:")]
public double Budget { get; set; } //dropdown
}
The built-in DefaultModelBinder in MVC will perform required and data type validation on value types like int, DateTime, decimal, etc. This will happen even if you don't explicitly specify validation using someting like [Required].
In order to make this optional, you will have to define it as nullable:
public double? Budget { get; set; }
You have to add the following line in the application_start (global.asax)
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Source: Unrequired property keeps getting data-val-required attribute
double is a value type. Value types always contain a value, even if you did not set one. That value is the default value for it's type (in this case 0.0). All value types are treated as required by the framework. The only way around this is to create a custom model binder, but that will not prevent the model from containing the default value (because there is no way to say that it wasn't entered).
So even if you create a custom binder, when you process your model, you won't be able to tell if someone entered 0 or whether that was just the default value.
Thus, the only real solution is to change your view model to use a nullable type, such as Nullable<double> (shorthand is double?).
You probably change Budget from a double to double?
You probably can try adding this attribute to the controller
BindExclude([Bind(Exclude="Budget")]) as well
Use Nullable or ? after attribute name.
Use [NotMapped] annotation , this removes the required validation in the flow you also use own display attributes
I have just encountered the problem with a project migrated to .Net 6.0, suddenly some fields started to be required even if there's no data annotation for it.
For example, in
public class LoginModel
{
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string ErrorMessage { get; set; }
...
}
I got the error : "The ErrorMessage field is required", which have of course no sense at all.
The project has <Nullable>enable</Nullable> feature enabled, it seem to cause this.
Simply rewrite property to
public string? ErrorMessage { get; set; }
To fix this (note the question mark)
You may also use:
services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Either ErrorMessageString or ErrorMessageResourceName must be set, but not both error using CreditCardAttribute

This is my model:
namespace MvcApplication2.Models
{
public class CreditCard
{
[CreditCard(ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "CardNumberInvalid")]
public string CardNumber { get; set; }
}
}
This is my Messages.resx:
Name Value
CardNumberInvalid Check your card number is correct
And this is my view:
#model MvcApplication2.Models.CreditCard
#Html.TextBoxFor(m => m.CardNumber);
In MVC version 3 this works without error. In MVC 4 when I go to this page I get an excpetion saying "Either ErrorMessageString or ErrorMessageResourceName must be set, but not both". This is only happening with the CreditCardAttribute. Other validation attributes such as RequiredAttribute work fine. I have only set the ErrorMessageResourceName. I have not set the ErrorMessageString, so do not understand what I have done wrong. Can anyone help please?
It's a known issue in .Net 4.5. Adding "ErrorMessage = null" named parameter should solve this.
Reference:
Reference link is broken now.
http://connect.microsoft.com/VisualStudio/feedback/details/757298/emailaddress-attribute-is-unable-to-load-error-message-from-resource-mvc
[CreditCard(ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "CardNumberInvalid", ErrorMessage = null)]
Adding the ErrorMessage = null will fix your problem.
I had this problem because I had implemented a RequiredAttributeAdapter, which was setting the ErrorMessageResourceName property automatically.
You can fix it by checking to see if the ErrorMessage property has been set before setting the ErrorMessageResourceName:
/// <summary>
/// Creates a new instance of the RequiredAttributeAdapter, used for switching the default required message
/// format
/// </summary>
public CustomMessageRequiredAttributeAdapter(
ModelMetadata metadata,
ControllerContext context,
RequiredAttribute attribute
)
: base(metadata, context, attribute)
{
if (string.IsNullOrEmpty(attribute.ErrorMessage))
{
attribute.ErrorMessageResourceType = typeof (ValidationMessages);
attribute.ErrorMessageResourceName = "PropertyValueRequired";
}
}
Since anyone who is using custom validation attributes and also wants to load error messages from resources for localization purposes, would face this problem i share my workaround here.
assume that you have a custom validation attribute like this one
[FileTypeMustBe("jpg")]
public HttpPostedFileBase MyFile {get; set;}
in your custom validation attribute add this code
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentCulture,
ErrorMessageString, name, ValidFileType);
}
ValidFileType is name of a property which takes the input argument of custom validation attribute (jpg here),well now we can decorate our model property the way we like it to be
[FileTypeMustBe("jpg", ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "WrongFileTypeError")]
public HttpPostedFileBase MyFile {get; set;}
as you see there's no need to add ErrorMessage=null anymore cause we took care of it in custom validation class. just do not forget if you had initialized any error message string in your custom validation , you have to remove it now and use FormatErrorMessage instead.
I had a simmilar issue with a custom ValidationAttribute.
In the IsValid method I was setting the ErrorMessage. The fix was to remove the assignation to the ErrorMessage propety...
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
//code before ...
this.ErrorMessage = this.FormatErrorMessage(validationContext.DisplayName); //NOT GOOD...
ValidationResult validationResult = new ValidationResult(this.ErrorMessage, //And using the ErrorMessage Here...
new[] { validationContext.MemberName });
return validationResult;
}
I was writting Unit test and they were pasisng only if i was running/debugging one by one. But when I click "Run All", only the first one was passing? They are not Linked in any ways...
So yeah, just remove the remove the assignation to the ErrorMessage propety
I hope it will help someone!
In my case, I was using ErrorMessage as "" in .Net Core 3.1 API.
[Required]
[RegularExpression("^[1-9]\\d*$", ErrorMessage ="")]
public int fieldName { get; set; }
I change to ErrorMessage ="Invalid Value Or some other message" and the issue is solved.
Replacing
[Required(ErrorMessage = "")]
with
[Required()]
worked for me, there is no meaning of keeping ErrorMessage with a blank string either
I ran into this when using a custom 'ValidationAttribute' that returned a ValidationResult instead of a bool. When I returned an unassigned string with the ValidationResult it would throw the error
Either ErrorMessageString or ErrorMessageResourceName must be set, but not both
When I returned ValidationResult(null) the field would never validate, it was always invalid. Looks like .NET looks for a ValidationResult to determine if the field is valid and not if it contains an error string. In order to get it to validate and get rid of the error I needed to return a null result.
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string errMsg = null;
// Do validation and assign the error message
return (!string.IsNullOrEmpty(errMsg)) ? new ValidationResult(errMsg) : null;
}
I had this same problem on a property that I was localizing. I had defined the ErrorMessageResourceType and then the ErrorMessageResourceName but by mistake put the ErrorMessage atrtribute on as well which threw the exception
[NotEqualTo("User_Name", ErrorMessageResourceType = typeof(LROResources.Global), ErrorMessageResourceName = "UserPasswordCannotBeUsername", ErrorMessage = "The password cannot be the same as your Username.")]
So in my case by just removing ErrorMessage I fixed the problem.

Remote ViewModel validation of nested objects not working

I have a class user which looks like this:
public class User
{
public int UserId { get; set; }
[Required(ErrorMessage = "A username is required.")]
[StringLength(20, ErrorMessage = "Your username must be 4-20 characters.", MinimumLength = 4)]
[RegularExpression("^[a-zA-Z0-9]*$", ErrorMessage = "Your username can only consist of letters and numbers.")]
[Remote("UsernameExists", "RemoteValidation", ErrorMessage = "Username is already taken")]
public string Username { get; set; }
[Required(ErrorMessage = "A password is required.")]
[MinLength(4, ErrorMessage = "Your password must have at least 4 letters.")]
public string Password { get; set; }
[Required(ErrorMessage = "An email address is required.")]
public string Email { get; set; }
}
For the Register functionality I have created a ViewModel that holds a User object and a string for the password confirmation:
public class RegistrationViewModel
{
public User User { get; set; }
[DisplayName("Password confirmation")]
[Required, Compare("User.Password", ErrorMessage = "The password do not match")]
public string PasswordConfirmation { get; set; }
}
The first problem I run into is that I can't seem to get the validation for Compare("User.Password") to work as it does not seem to find the property on the user. Is there any way to validate the PasswordConfirmation property against the User.Password property?
The second problem is the Remote validation of the Username field. I followed David Hayden's tutorial at http://davidhayden.com/blog/dave/archive/2011/01/04/ASPNETMVC3RemoteValidationTutorial.aspx but the parameter username in the UsernameExists method is always null. Am I missing something here?
Edit:
I'm sorry but I was actually not clear enough on the error I receive for the password comparison. It works fine when filling in the fields, if the passwords do not match I will receive an error. However, when submitting the form I get the following error in the validation summary: Could not find a property named UserToRegister.Password.
Edit 2:
I have figured out part of the problem thanks to Joe's post. The remote validator posts back URL/?UserToRegister.Username=temp which obviously does not match the username parameter of my controller action. In order to map my action parameter to UserToRegister.Username the following is required:
public ActionResult UsernameExists([Bind(Prefix = "UserToRegister.Username")]string username)
This now correctly passes the parameter to the method. However I still get the error when using the Compare attribute on the password field.
Thanks.
The issue with the validation of the PasswordConfigurmation property against the User.Password property is caused by a bug in in the 'jquery.validate.unobtrusive.js' file.
Originally, the jquery 'equalTo' function is:
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
setValidationValues(options, "equalTo", element);
});
You just need to modify this line:
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
to:
element = $(options.form).find(":input[name='" + fullOtherName + "']")[0];
Note the addition on the single quotes around the 'fullOtherName' selector. Once you've made this change, the client side validation works as expected.
For the remote validation part nothing jumps out at me. It might be helpful to open up firebug and see what the request that is being fired looks like. You should see something roughly like this if everything is properly wired up...
http://localhost:14547/[Controller]/[ActionName]?[ParamName]=[paramValue]
From the request you provided, you can either use a prefix like you ended up doing or you can make your action take a user named UserToRegister and then within the action access the UserName property. This is the recommended way of dealing with remote validation of objects and might be a little easier to think about than using a Bind attribute.
For the compare validation, it appears that on the client side validation is succeeding but on the server side validation fails because the validation context does not contain a property named User.Password, only a property named User.
Inheritance seems like a standard way of adding functionality in this case. How about having your RegistrationViewModel derive from the UserViewModel:
public class RegistrationViewModel : UserViewModel
{
[DisplayName("Password confirmation")]
[Required]
[Compare("Password", ErrorMessage = "The password do not match")]
public string PasswordConfirmation { get; set; }
}
and:
public ActionResult UsernameExists(string Username)
{
...
}

Change default "The {0} field is required" (ultimate solution?)

Good day!
I've the following ViewModel class I use for login form:
using System.ComponentModel.DataAnnotations;
...
public class UserLogin : IDataErrorInfo
{
[Required]
[DisplayName("Login")]
public string Login { get; set; }
[Required]
[DisplayName("Password")]
public string Password { get; set; }
[DisplayName("Remember Me")]
public bool RememberMe { get; set; }
#region IDataErrorInfo Members
// This will be a Model-level error
public string Error
{
get
{
if (!WebUser.CanLogin(Login, Password))
{
return Resources.ValidationErrors.InvalidLoginPassword;
}
else
{
return String.Empty;
}
}
}
// All is handled by DataAnnotation attributes, just a stub for interface
public string this[string columnName]
{
get
{
return string.Empty;
}
}
#endregion
}
And this in Global.asax:
DefaultModelBinder.ResourceClassKey = "BinderMessages";
ValidationExtensions.ResourceClassKey = "BinderMessages";
The resource file BinderMessages.resx is placed inside App_GlobalResources it has two keys InvalidPropertyValue (which works) and PropertyValueRequired which doesn't and gives me default message.
Question: Is it possible to modify this message, or it's tied to DataAnnotations?
I've found many posts about this, but without solution. For now I just fallback to this:
[Required(ErrorMessageResourceType = typeof(Resources.ValidationErrors), ErrorMessageResourceName = "Required")]
You can create a custom ValidationAttribute that extends RequiredAttribute and sets the values there. Something like:
public class MyRequiredAttribute : RequiredAttribute
{
public MyRequiredAttribute()
{
ErrorMessageResourceType = typeof(Resources.ValidationErrors);
ErrorMessageResourceName = "Required";
}
}
Then decorate your Model with your custom attribute.
The default message is compiled into the DataAnnotations assembly in the resource file under System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resources and is RequiredAttribute_ValidationError=The {0} field is required.. So to answer your question, yes, that message is part of DataAnnotations.
Edit: PropertyValueRequired is used for errors on null values with non-nullable types. As mentioned below PropertyValueInvalid is used for type conversion errors.
I've done an approach using a singleton class to provide the translations. You still need to derive all attributes as suggested by #bmancini. The upside with my approach is that you can use multiple string tables (or switch translation source) without having to modify any other logic.
Since my blog entry is rather large, I'll just provide a link:
http://blog.gauffin.org/2010/11/simplified-localization-for-dataannotations/

ASP.NET MVC: DataAnnotations - Show an error message indicating that a field must be numeric

There appears to be something of a hole in the way DataAnnotations works in that a user entering in some text into a field that will go into an int will never reach the DataAnnotations code. It kicks off a model binding error and displays the error to the user "The value 'a' is not valid for the XXXX field."
Anyway, it's all very nice that it automatically handles this situation, but I actually want to display an error message indicating the problem eg. "The value 'a' is not numeric. Please enter in a numeric value for the XXXX field".
I have tried the solutions set out How to replace the default ModelState error message in Asp.net MVC 2? and ASP.NET MVC - Custom validation message for value types, but I can't get them to work.
It appears that my resource file is not being read at all, since here (http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultmodelbinder.resourceclasskey.aspx) it states "If the property is set to an invalid class key (such as a resource file that does not exist), MVC throws an exception." and even if I change the line to DefaultModelBinder.ResourceClassKey = "asdfasdhfk" there is no exception.
Anyone have any ideas?
EDIT: Here is some code. All of it is working minus my Messages.resx file's messages are not being used. The code for Messages.resx is auto generated so I won't include it.
So entering "a" into ProcessOrder results in a generic message rather than what I have entered into Messages.resx for PropertyValueInvalid (and InvalidPropertyValue for good measure).
Application_Start method
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder(); //set dataanooations to be used
DefaultModelBinder.ResourceClassKey = "Messages"; //set data annotations to look in messages.resx for the default messages
ValidationExtensions.ResourceClassKey = "Messages";
}
Entity Class
[MetadataType(typeof(GLMetaData))]
public partial class GL
{
}
public class GLMetaData
{
public int TransRefId { get; set; }
[DisplayName("Process Order")]
public int? ProcessOrder { get; set; }
[DisplayName("Trans Type")]
[StringLength(50)]
public string TransType { get; set; }
[StringLength(100)]
public string Description { get; set; }
[DisplayName("GL Code")]
[StringLength(20)]
public string GLCode { get; set; }
[DisplayName("Agents Credit No")]
[StringLength(50)]
public string AgentsCreditNo { get; set; }
[Required]
public bool Active { get; set; }
}
Controller Action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(GL glToBeUpdated)
{
try
{
if (!ModelState.IsValid)
return View(glToBeUpdated);
//set auto properties
glToBeUpdated.UpdateDate = DateTime.Now;
glToBeUpdated.UpdateUser = this.CurrentUser;
glDataLayer.update(glToBeUpdated);
glDataLayer.submitChanges();
return RedirectToAction("Index");
}
catch
{
glDataLayer.abortChanges();
throw;
}
}
What I did to combat a similar issue was to clear the model state, validate against ModelState["XXXX"].Value.AttemptedValue instead of against the nulled value caused by an trying to put an invalid value into the Model's property, populating the error messages and resetting the Model values.
That way I can have the error messages I want and if necessary offer more than one ("a value is required" or "the value must be numeric").
I have battled this for most of the day on MVC4 RC. No matter what i set
DefaultModelBinder.ResourceClassKey
to it never seemed to work. It also never threw an exception when I assigned junk.
This is what I was using to assign the value (to no avail):
DefaultModelBinder.ResourceClassKey = typeof(App_GlobalResources.ValidationMessages).Name;
In the end I decided to tackle this error message on the client side and override the data attribute that jQuery uses to display the message.
#Html.TextBoxFor(m => m.Amount, new Dictionary<string,object>(){{"data-val-number","Invalid Number"}})
this is working how I need it to.
Ironically this works too:
#Html.TextBoxFor(m => m.Amount, new Dictionary<string, object>() {{ "data-val-number", HttpContext.GetGlobalResourceObject("ValidationMessages", "PropertyValueInvalid") } })
Here I have taken Contact number field as string but with Range Attribute so can provide numeric validatioin to use if from your Resource file .
[Required(ErrorMessageResourceType = typeof(Global), ErrorMessageResourceName = "ContactNumberRequired")]
[Range(0, int.MaxValue, ErrorMessageResourceType = typeof(Global), ErrorMessageResourceName = "ValidContactNumber")]
[Display(Name = "Contact Number")]
public string ContactNumber { get; set; }
So now here provided ErrorMessageResourceName as key . You can customize and use it also in Multi Language

Resources