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.
Related
I'm new to FluentValidation and am trying to create a validator that accepts some context/parameters at validate time. I've created a custom validator and in the constructor I have something like:
RuleFor(request => request.someField).Custom((request, context) => {
var foo = context.ParentContext.RootContextData["someDependency"];
});
And in the calling code I do:
var validator = new FooValidator();
var context = new ValidationContext<SomeRequest>(request);
context.RootContextData["someDependency"] = someDependency;
validator.Validate(context);
which causes:
System.Collections.Generic.KeyNotFoundException: The given key 'someDependency' was not present in the dictionary.
Any ideas? The reason I want to pass in some context parameters is that they come from the database. If I instead pass that into the validator constructor, then by the time the validate method is called, those context parameters might be out of date. I also don't want to do the fetching from the database in the validator constructor as I will also need to fetch the same data before/after the validate method is called, and database caching is not possible in this scenario, so I'd like to avoid the unnecessary database roundtrips. I've read and am doing what seems to be the same as what is described https://docs.fluentvalidation.net/en/latest/advanced.html#root-context-data
As mentioned in my OP comment, the code looks sound but it's likely failing at the MVC validation pipeline stage and never makes it to your Validate invocation. With the former as it stands you've not added your dependency to the dictionary so it barfs.
There's probably a couple of ways to solve it. My first thought would be to introduce a rule set so this rule only executes server-side as part of your Validate invocation. There's a whole section on rule sets in the doco which covers it pretty well. You may need to combine it with a CustomizeValidator attribute so that the rule set doesn't get executed in the MVC validation pipeline (I've never had to when using a server-side rule set but I've mentioned it for completeness).
The nice thing with this is that you probably won't need to change much of your existing code; you've mentioned you load a number of dependencies into the validation context so it could be a good fit.
Another methodology that looks good, but one that I haven't tried myself, would be to populate the validation context in the BeforeMvcValidation validation interceptor. The value of this option is going to depend on how you gather those dependencies and whether they are used for anything other than validation. It'd probably require more effort than a rule set based on your implementation description as well.
Let's say I have one view model. It has one required Name property. And I have disabled client-side validation. I have this code in my action method:
if (!ModelState.IsValid)
{
return View(model);
}
So, everything works fine. It will highlight the required field after post. But, I can't understand that which jQuery validaion function do this process? How, jQuery Validation detects that the form has been submitted once?
I want to find that code, because I want to change it slightly. For example, I have my own helpers, which has custom validation logic. For now, my custom helper validation are not showing after invalid Post. And, I want to add my logic to the built-in function, which I CAN NOT FIND ANYWHERE.
Firstly, if you have disabled client side validation, jquery validation has nothing to do with it (you have disabled it!). To briefly explain what happens when you post and return the view.
The DefaultModelBinder initializes a new instance of you model
The DefaultModelBinder then reads the form data (name/value pairs)
and if a property name matches one of the form data values, its
property is set (assuming its valid) and its value is also added to
ModelState. If the value is not valid, the property is not set but
its value is added to ModelState (the attemptedValue) along with
a ModelState error
When you return the view, your #Html.ValidationMessageFor() method
reads the ModelState values and if there is an error associated
with the property, the error message is added to the html generated
by the ValidationMessageFor() method and the relevant class name
(which highlights it) is added
You can inspect the source code for the DefaultModelBinder and ValidationExtensions if you want to see more detail of how these work.
As for "I want to find that code, because I want to change it slightly", then DONT. You have not indicated what you trying to do, or shown any code for your html helper extension method, but html helpers do not (and should not) contain validation logic. They are responsible for generating html based on a property and the validation attributes applied to that property.
If you have custom validation logic for a property, then you create an attribute that inherits from ValidationAttribute (and if you also want client side validation then it also needs to implement IClientValidatable). A good guide for creating your own validation attributes is this article.
Mvc has its own validation that is not server side and works with the data annotations you set on your model. On post it simply goes to the controller then checks the modelstate errors if its valid it runs your code in the function, if not it returns the model with its errors. If you had jquery validation it would never go to the controller in the first place. When server side validation is enabled the validation is done before the form is sent to the controller. Without jquery it is validated at the controller. If not what you're looking for please let me know
I am now working on an existing asp.net MVC application which has a few submit button in one web page(e.g. ignore, delete, update, submit...) And they all send a post request to the server and the server will perform different operation based on the request action type (e.g. ignore, delete, update, submit).
However, an issue is raised that the model validation will always triggered regardless of the operation. According to the business rule, we only need to perform validation for some certain operations. I can clear the error in the modelstate after the validation. (for example MVC3 Remove ModelState Errors).
However I am hoping there is a better way to just bypass the model validation according to the operation parameter from the client.
BTW: I am not allowed to significantly change the way how it works (e.g. send to another action for those operation that does not care about the validation), so I am hoping there is some trick that I can use to achieve this easily.
I assume now you are checking model state errors like...
if (ModelState.Valid)
{... valid and do something...}
If so, you can include some additional checking before hand that will be considered in your conditional. For instance, if it is a delete submit, you can check that before hand.
bool isDelete = ***check some value***
if (isDelete || ModelState.Valid)
{... valid and do something...}
This way even if the model state is invalid, it will still move forward.
One thing to consider is you will need to set something in the model to tell you what action is happening. This probably means using javascript to capture the submit, set a model field, and then perform the submit.
I'm using ASP.NET MVC2.
I love how I can annotate my model's fields and check ModelState.IsValid.
The obvious reason to check it is when doing validation, but should you always check it in case new validation rules are applied to the model?
That way you don't forget / need to check whether the controller checks IsValid.
Is there some reason not to do this check in all cases? Maybe just when the controller action has side-effects (DB-writing etc)?
but should you always check it in case new validation rules are
applied to the model?
You should do this check always else you end up persisting models that don't have valid state.
Generally, in asp.net-mvc, models passed to actions are view models, and they contain all and only data needed for action to act. If that data is invalid, theoretically it should be impossible for action to do its job.
ModelState.IsValid ensures that all data needed for action is in good state, ready to be acted on. I do not see reason where you would not want to validate that data.
You should always check if the model is valid immediately before attempting to use the data collected in the model to do something. That's the purpose of validation in the first place.
It looks obvious to mention, but i will give it a shot.
There is NO need to check model state when you are NOT posting your model. The common scenarios are when you are getting your data from service and displaying on a get action.
I have a model class :
public class YearlyChageRate
{
public int Year { get; set; }
public double Rate { get; set; }
}
and I want to check that Yeae is unique or no and in condition Year is not unique application show an error message to users.How can I check the Year filed is repeated or not?
Here is a good example:
http://tugberkugurlu.com/archive/asp-net-mvc-remote-validation-for-multiple-fields-with-additionalfields-property
And here too: MVC validation for unique
You can use Remote attribute in your model to perform check for unique value in database.
This is official example of Remote attribute: http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx
And one more: http://www.a2zdotnet.com/View.aspx?Id=198
You could use the [Remote] validation attribute on your view model.
Although you can use DataAnnotations attributes for validation and the [Remote] attribute for checks against the DB, it's not a very good design choice.
Let me explain:
data access is a data-layer matter
validation is a business-layer matter
user input and feedback is a ui matter
With DataAnnotations, you're mixin 3 in 1. It can be faster, but surely not well designed.
You could try a more disciplinate approach, like this:
Have a method at business level that will take your object as a parameter, perform validation internally using a validation framework of your choiche;
This method will call the data access to persist the object only if the validation passed;
This method will always return to the UI the validated object, plus a collection of fields/errors if anything didn't validate;
When you read the output of the method in your ui, you can either display a success page if there were no errors, or redisplay the form with the validation errors returned. To do this, the use of the PRG pattern is highly recommended, as you should never display a page on a POST method. Google for the PRG pattern to learn more about it. MvcContrib has a nice ActionFilter called ModelStateToTempData to make the implementation of the PRG pattern something trivial.