Is there a way to change the default error message for an in in FluentValidation?
We are able to set up validations for more complex types but the simple 'the data you entered isn't an int' style things we can't seem to get at.
The built in error for these is: 'the value x isn't valid for y' or something along those lines - is there a way to override these?
There's no easy/clean way to achieve that. The first possibility is to override the DefaultModelBinder.ResourceClassKey property in your application start and point it to a custom resource file:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
DefaultModelBinder.ResourceClassKey = "Messages";
}
and then define the key PropertyValueInvalid inside App_GlobalResources/Messages.resx.
Another possibility is to use a backing field on your view model as suggested by Jeremy Skinner.
The reason for this is that this error message is generated by the default model binder before any validation can occur on the field. Before you can validate the field it must first be assigned a value. And since you are attempting to convert a string which doesn't represent a valid integer into an integer during model binding, the default model binder assigns a default message.
You can override that as well.
Follow the below link
http://fluentvalidation.codeplex.com/wikipage?title=Customising
Related
I have a Blazor application. In this application I have several models with various ValidationAttributes.
To validate these models I use an EditForm from Microsoft.AspNetCore.Components.Forms. On this form there is a parameter Called EditContext where I call the Validate() method to validate my models.
The validation itself works fine. However the order of when validations are run seems to be based on the type, like this:
Required
Other(Like Range)
IValidatableObject
This results in Required validations being validated first and only after these are valid in the model the other validations are running.
What I want is for all validations to run at the same time.
Does anyone know how to achieve this in Blazor?
Thanks
What I want is for all validations to run at the same time.
Not sure what you mean? All registered validations are run when you call Validate. There's has to be a sequence. If you want to change the sequence then you need to write your own validator.
the order of when validations are run seems to be based on the type
Validate on the edit context looks like this. It simply invokes any delegates registered with the OnValidationRequested event.
public event EventHandler<ValidationRequestedEventArgs>? OnValidationRequested;
public bool Validate()
{
OnValidationRequested?.Invoke(this, ValidationRequestedEventArgs.Empty);
return !GetValidationMessages().Any();
}
DataAnnotationsValidator or whatever validator you use registers a handler on this event.
In your case the validator is finding fields to validate by searching through the properties in the Model (referenced in EditContext) for specifc attributes. The first attribute it looks for is Required, ....
I'm apparently not allowed to write comments - only answers - but you're right and what Shaun Curtis says is definitely wrong. For anybody doubting this there's a gist here.
When using <DataAnnotationsValidator /> the validation attributes on the model are processed first - only once all of the attribute validation rules pass will the IValidatableObject.Validate method be called.
The functionality is by design - IValidatableObject is to validate the entire object once all of its properties have been filled out. Why is IValidatableObject.Validate only called if property validation passes?
I think Required validation is checked first for a reason. All subsequent validations can and must be run only after the property has a value.
Otherwise, all the other validations would fail by default. It's the framework just reminding you that you forgot to type in a field. After you supply the value, then it goes on to validate its format and what not.
I hope that makes sense.
please help me with this:
I have model with property of Enum type. This property is required, but on View initial value must be empty. Will show watermark..
If I understand correct than model will have not nullable property. But viewModel will have nullable. Is this right way?
Looks like in this case:
need create viewModel
viewModel and model will have different data sometimes
viewModel need logic for set and get correct values to/from model or get null in first time and leave as is model
viewModel need one more validation rule
Other way is:
Model will have nullable property and required validation:
can bind to model
model does not "correspond to reality"
we need always expose data from nullable enum and forgot about null? or handle it (convert to DTO or something like this)
nullable property is only UI requirement and can be changed in future
Having the (domain) model use a non-nullable enum suggest that the value MUST have a valid value for use case and / or data integrity.
Having the requirement on the UI to allow a non-valid value (initial or otherwise) will result in 1 of 2 things:
When the View posts a null value (via a dedicated ViewModel) and checks are performed to ensure its not null (I assume that the user selects the "Please Select" value from a select box) the server will respond with an error message saying something like "Please select a valid value blah blah".
Or, the server will allow the null from the View Model and default the domain model property to some predetermined sensible value.
In my experience this kind of setup leads to a frustrating user experience because having the UI present an invalid selection option that only feedsback upon submit (or using some frontend / client validation) is rather annoying (especially on a long form, Etc).
Perhaps you would be better rethinking that requirement so the UI only presents valid enum values for selection and optionally make the default one a sensible value.
Having said that if you really want the UI to not have a valid initial value then make a view model with a nullable version and validate on the server as you suggest. As far as changing the (domain) model with a nullable, you already seem concerned that it doesn't "correspond to reality" which is a good impulse considering you already mentioned that this is a UI only requirement, thus place the detail in that layer and keep your domain modals as close to reality as is needed to satisfy your use cases and / or business requirements.
I followed Fluent documentation and I haven't found any option to overwrite default error format that is something like "'{propertyName}' must be something.". I have many validators and I won't rewrite them to .WithMessage("...").
Is there any option to change default message format?
I would like to have a similar interface to PropertyNameResolver that offers smart interface to change property name.
You can overwrite the messages globally by modifying the ValidatorOptions.ResourceProviderType as noted on the localization page.
You only have to define the strings that you would like to change as it will use the default string if no override is specified.
This is more of a curiosity for me than something I actually need to do. Is there a way to tell the model binder that it should only attempt to find a value using a specific IValueProvider?
ie: Let's say I have a model whose Id property I want to be bound specifically from the QueryStringValueProvider. The way the default value provider works is a first-with-value-wins situation. So if I have a value provider registered before the QueryStringValueProvider, and that provider returns a value first, then the query string value is ignored entirely.
I know I can make a custom ModelBinder and deal with it that way, but I'm wondering if there's a built in way of handling this already(like popping an attribute on the property or something)?
I'm trying to set a default value to a field with FluentValidation when the provided value is invalid (ex: if the provided language isn't supported, put an error message and default the language to english). I know it's not a good practice to change a value in a validation but in the case of language, I need it to be properly set for further validations and to display the error messages.
How can I do that ?
Thanks
You can't do this within a fluent validation validator. The validator class should only be concerned with providing validation: this is its single responsibility.
To do what you describe, you could perform the validation and then check for the language related error at which point you could set the default value.
Or perhaps you could default the language value prior to validation - it's difficult to make a recommendation without any code.