I have a binding with data validation implemented by IDataErrorInfo. When data validation fails, the property is set. How could I avoid the change of the property when data validation fails?
Thank you very much.
I don't think IDataErrorInfo can be used to avoid the property value change if value is not valid. It only helps binding proper error message to the UI so that the user can change given value to valid value.
To avoid invalid values being set in your properties, if they are CLR Properties, use validation methods in setters and if they are Dependency Properties, use validation callback to properly validate the values.
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.
Please note that I am using N-Tier Entity Framework (http://ntieref.codeplex.com/) with (WCF) SmartClient Winforms application. Using Data Annotations to perform client side validation, I would like to (mimic MVC) choose to immediately display a Data Annotation Error Message to the User when they type in a value, and/or choose to wait to display all the Error Messages for all the Entity Properties when the User clicks the save button (possibly using Validator.TryValidateObject), but prior to calling context.SaveChanges().
Currently, when the property value changes and the User attempts to change control focus, the Entity OnPropertyChanging() method executes, the property is checked for validation (ValidateProperty()) and if it fails validation (due to a Data Annotation) an exception is thrown and the control will not lose focus, but no exception/error message is passed/displayed.
How can I get the Data Annotation Error Messages available for client side validation?
#ChristofSenn Do you have any suggestions?
N-Tier Entity Framework provides multiple validation mechanisms:
Early validation performed while setting a property value, throws if invalid and prevents actually setting invalid values (this is enabled by default)
IDataErrorInfo lets you validate a property's current value (requires IsValidationEnabled=false to be able to actually set invalid on properties)
ValidateProperty(string propertyName, object value) allows validating values without actually trying to apply the value to the property.
In your case I presume you need to set IsValidationEnabled=false as othervise WinForms DataBinding fails to set invalid values in the first place and then doesn't get back any validation error using IDataErrorInfo interface, since the value wasn't actually set. The property IsValidationEnabled is available on DataContext, EntitySet, and Entity level.
#ChristofSenn I appreciate your response.
1) To utilize early validation of a control/property, we are using the BindingComplete event of a BindingSource control to display the validation exception (Data Annotation Error Message).
2) To utilize IDataErrorInfo, we have set IsValidationEnabled=false and written the following code to get a string of Data Annotation Error Messages. Please let me know if there is a different way to utilize the IDataErrorInfo.
context.EntitySet.IsValidationEnabled = false;
NTier.Common.Domain.Model.Entity tempEntity = (NTier.Common.Domain.Model.Entity)entityName;
string errorMessages = ((System.ComponentModel.IDataErrorInfo) tempEntity).Error;
//Where errorMessages contains a string of Data Annotation Error Messages.
3) We are able to successfully obtain the Data Annotation Error Message by using entity.ValidateProperty(propertyName, propertyValue) and catching the exception.
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.