Remove property name from validation message - c#

Is it possible to remove property name form the validation message? For example, instead of:
Field 'Name' should not be empty.
I want to show:
Field should not be empty.
I need to do this global, for all validators.

You can do this using the localization customization like so to make the change globally. You can then of course override specific errors with a custom format if you need a one-off change.
ValidatorOptions.ResourceProviderType = typeof(MyResources);
...
public class MyResources {
public static string notempty_error {
get {
return "Field should not be empty.";
}
}
}

easiest way would be to pass a custom message. You can also override it so it always uses that message.
[Required(ErrorMessage = "Field should not be Empty")]
public string Name { get; set; }

Related

How to return a key for the whole model in FluentValidation

Imagine, you have this model
public Class SomeModel
{
public string someString1 { get; set; }
public string someString2 { get; set; }
}
Now you want to validate this model. In FluentValidation you write this.RuleFor(m => m.{property} for each property on the model/class and when a validation error occurs, you get the key of the property that failed validation and a message.
Now, what i am wondering about, is how you can set a key for the whole model when it returns an error from validation, which validates two or more properties. (e.g. this.RuleFor(m => m).TestIfPropsAreEqual(); ) What is the correct way to approach this problem? I don't really want to write the method on a property, because that wouldn't be correct, because you are validating the whole model not a specific property.
EDIT: Forgot to mention that when validating the whole model, the returned key is empty.
https://fluentvalidation.net/start#overriding-the-property-name is the answer. I can give the a name to class or new name to a property.

Validation error not getting localized string

I'm having an issue with a validation error in ASP.NET MVC 4.
I've applied a RegularExpression rule for a field which will accept only numeric input. Should the data contain any other character it should display an error message.
[RegularExpression("^[0-9]*$", ErrorMessageResourceType = typeof(Resources.General), ErrorMessageResourceName = "CodeMustBeNumeric")]
public string Code { get; set; }
Problem is, no matter what's the current culture setting, it always displays the default resource and not the localized one. Some more details to follow.
My resources:
The result:
As you can see, the current culture for all strings is Italian, but not for the validation error. What am I doing wrong?
I thought I was doing something wrong and there was an out-of-the-box way to solve this, but with a deeper search I found out the common solution is just creating a custom validation attribute which inhreits from the ASP.NET one.
So I did, and it works fine. Should anyone need it, here it is:
public class CustomRegularExpressionAttribute : RegularExpressionAttribute
{
public override string FormatErrorMessage(string name)
{
string currentLang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
CultureInfo ci = new CultureInfo(currentLang);
return HttpContext.GetGlobalResourceObject(ErrorMessageResourceType.Name.ToString(), ErrorMessageResourceName, ci).ToString();
}
public CustomRegularExpressionAttribute(string pattern)
: base(pattern)
{
}
}
And the new call:
[CustomRegularExpression("^[0-9]*$", ErrorMessageResourceType = typeof(Resources.General), ErrorMessageResourceName = "CodeMustBeNumeric")]
public string Code { get; set; }

How do I get the Validation message to disappear after adding a model error MVC?

In my view I have a check box and a text box if the check box is checked then I require the text box to be filled with some text. To do this I call
ModelState.AddModelError("item", "Please enter some text.");
only if the checkbox returns true and the text box isempty
when my page re-displays I receive the proper message where I have
#Html.ValidationMessageFor(model => model.item)
but I would like the text to go away after a use types something in the text box, without the user having to hit submit like it does with data annotation. How can I fix this?
I'm using c# Asp.net 4 with entity framework 5
ModelState.AddModelError is server-side validation, so the error message will not go away until you post to the server.
If you want the functionality you describe, you can define a custom validation attribute and apply it both client side and server-side. For example, you can define a "RequiredIf" custom validation attribute, which would make a field required if a certain other condition is met (in this case, if another property is true):
public class RequiredIfAttribute : RequiredAttribute
{
private String PropertyName { get; set; }
private Object DesiredValue { get; set; }
public RequiredIfAttribute(String propertyName, Object desiredvalue)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
Object instance = context.ObjectInstance;
Type type = instance.GetType();
Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
if (proprtyvalue.ToString() == DesiredValue.ToString())
{
ValidationResult result = base.IsValid(value, context);
return result;
}
return ValidationResult.Success;
}
}
Register it in your global.asax:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),typeof(RequiredAttributeAdapter);
Then you can use it like this:
public class YourModel {
// This is the property tied to your checkbox
public bool YourBooleanProperty { get; set; }
[RequiredIf("YourBooleanProperty", true)]
public string Item { get; set; }
}
You could also leverage the JQuery Validate plugin to perform the same conditional validation client-side.
Try with jquery, attach an eventListener to the field and remove the class CSS that MVC added to the field and hide the validation label

Is it wrong to dynamically add "data-val" and "data-val-required" in the View?

I have a ViewModel that I can decorate with the [Required] attribute (see below). I've come to the point where I need to let the client control which fields are required or not. They can configure this trough XML and all this info is stored in the Model when it's first created. Now I have fields that are not decorated with [Required] but still need to get validated (as per "user settings") before submitting (for example the Phone field).
public class MyBusinessObjectViewModel
{
[Required]
public string Email { get; set; } //compulsory
public string Phone { get; set; } //not (yet) compulsory, but might become
}
If the user will not enter the Phone number, the data will still get posted. Wanting not to mess with custom validators, I just add the "data-val" and "data-val-required" attributes to the Html, like this:
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("data-val", "true");
dict.Add("data-val-required", "This field is required.");
#Html.TextBoxFor(x => x, dict);
This forces the client side validation for all the properties that are dynamically set as required. Is this good practice? What kind of side effects can I expect?
You should look into extending the meta model framework with your own metadata provider to do the actual binding between your site's configuration and the model metadata. You can actually set the required property flag to true on the property model metadata during the metadata creation process. I can't remember for sure whether this causes the built in editor templates to generate the attribute, but I think it does. Worst case scenario you can actually create and attach a new RequiredAttribute to the property, which is a tad bit kluggy, but works pretty well in certain scenarios.
You could also do this with IMetadataAware attributes, especially if Required is the only metadata aspect your users can customize, but the implementation really depends on what you're trying to do.
One major advantage of using a custom ModelMetadataProvider in your specific case is that you can use dependency injection (via ModelMetadataProviders) to get your customer settings persistence mechanism into scope, whereas with the data attribute you only get to write an isolated method that runs immediately after the metadata model is created.
Here is a sample implementation of a custom model metadata provider, you'd just have to change the client settings to whatever you wanted to use.
UPDATED but not tested at all
public class ClientSettingsProvider
{
public ClientSettingsProvider(/* db info */) { /* init */ }
public bool IsPropertyRequired(string propertyIdentifier)
{
// check the property identifier here and return status
}
}
public ClientRequiredAttribute : Attribute
{
string _identifier;
public string Identifier { get { return _identifer; } }
public ClientRequiredAttribute(string identifier)
{ _identifier = identifier; }
}
public class RequiredModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
ClientSettings _clientSettings;
public RequiredModelMetadataProvider(ClientSettings clientSettings)
{
_clientSettings = clientSettings;
}
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
// alternatively here is where you could 'inject' a RequiredAttribute into the attributes list
var clientRequiredAttribute = attributes.OfType<ClientRequiredAttribute>().SingleOrDefault();
if(clientRequiredAttribute != null && _clientSettings.IsPropertyRequired(clientRequiredAttribute.Identifier))
{
// By injecting the Required attribute here it will seem to
// the base provider we are extending as if the property was
// marked with [Required]. Your data validation attributes should
// be added, provide you are using the default editor templates in
// you view.
attributes = attributes.Union(new [] { new RequiredAttribute() });
}
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
// REMOVED, this is another way but I'm not 100% sure it will add your attributes
// Use whatever attributes you need here as parameters...
//if (_clientSettings.IsPropertyRequired(containerType, propertyName))
//{
// metadata.IsRequired = true;
//}
return metadata;
}
}
USAGE
public class MyModel
{
[ClientRequired("CompanyName")]
public string Company { get; set; }
}
public class MyOtherModel
{
[ClientRequired("CompanyName")]
public string Name { get; set; }
public string Address { get; set; }
}
Both of these models would validate the string "CompanyName" against your client settings provider.
Not wanting to mess with custom validators, so you messed in the View obfuscating the logic of your validation by removing it from the place where it is expected to be found.
Really, don't be afraid of creating a custom attribute validator. What you are doing right now is getting a technical debt.

How to create a custom Compare attribute with client-side validation?

The title says it all, but I'll add a bit of background here.
Until recently, I've been using MVC's already-written CompareAttribute to compare two values, in this case a password and its confirmation. It's worked well, except this attribute does not display the display name, set by the [Display(Name = "Name")] attribute of the property being compared.
Here are the two properties being compared:
[Required]
[Display(Name = "New Password")]
public string New { get; set; }
[Compare("New")]
[Display(Name = "Confirm Password")]
public string ConfirmPassword { get; set; }
The validation message reads as follows:
'Confirm Password' and 'New' do not match.
This works, but it's obviously not as good as it should be. The New should read as New Password, as specified by the Display attribute.
I have gotten this working, although not completely. The following implementation (for some reason) fixes the issue of not getting the specified name of the property, but I'm not sure why:
public class CompareWithDisplayNameAttribute : CompareAttribute
{
public CompareWithDisplayNameAttribute(string otherProperty)
: base(otherProperty)
{
}
}
Now, even though this works, client-side validation does not work. I've received an answer in another question that suggests using something like this
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CompareWithDisplayName), typeof(CompareAttributeAdapter))
in my Global.asax, however the CompareAttributeAdapter doesn't actually exist.
So here I am. I've got the Display attribute being used properly by my custom CompareWithDisplayName attribute, but client-side validation missing altogether.
How can I make client-side validation work with this solution in the cleanest way possible?
If you want your custom compare attribute to work with clientside validation you will need to implement IClientValidatable. This has GetValidationRules which is where you can do any custom validation you might wish.
Example
public class CompareWithDisplayNameAttribute : CompareAttribute, IClientValidatable
{
public CompareWithDisplayNameAttribute(string otherProperty)
: base(otherProperty)
{
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
ModelMetadata metadata, ControllerContext context)
{
// Custom validation goes here.
yield return new ModelClientValidationRule();
}
}

Categories