How to use C# FluentValidation ValidationContext.RootContextData - c#

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.

Related

How to validate all properties in a model at the same time?

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.

Share data between custom attribute and the method

How can I get dynamic data shared between a custom action attribute and the action method?
My scenario, I am utilizing a custom action attribute to cache data in Redis. In this custom action attribute, I am logging metrics for how long it takes to get data from the cache vs getting it from continuing with the code. For some instances, I cannot utilize this custom action attribute and I'm calling cache methods like, _cache.TryGetAsync(key); inside the action method. TryGetAsync is an extension method I wrote that just wraps the GetAsync(key) call in a try/catch so that if the call to Redis fails, it will continue with getting the data from continuing with the code.
I would still like to try and log metrics when the code is making direct calls to cache via the try extension methods that I wrote.
I was thinking about creating a CacheLogging attribute that I could place on the action method. Then, in the BeforeActionExecutionAsync, I could start the timer and in AfterActionExecutionAsync, stop it and log. But, I need the try extension methods to set the context of where the data is retrieved.
For example, TryGetAsync would set the context to FromCache. Then, TryAddAsync would set it to FromServer. If TryAddAsync is called, that means that the data was not found in the cache and continued to get it from the code and populated the cache with this new data.
The problem is, I can't figure out how to reliably set this context in the method so that the attribute can read it in the AfterActionExecutionAsync. I thought about DIing a Singleton ICacheContext that the CacheLogging attribute would have access to and could be passed as an optional parameter into the try extension methods. But, with the possibility of the action method being called simultaneously multiple times, the Singleton would need some sort of Dictionary with a unique id per call that both the CacheLogging attribute and the try cache attribute would somehow know that way they knew which call the context was for. But, parameters need to be static/const/etc to be sent to the CacheLogging attribute.
You don't store performance in attributes.
If you need to store performance, define global variables that track performance for different methods and commit the data to your datastore every x, or write it to a (text) log.
You should try an AOP approach using Castle Windsor interceptors. See: https://www.tabsoverspaces.com/233716-simple-caching-interceptor-aspect-for-castle-windsor

Overriding the PageModel() constructer for setting up default properties (Razor Pages)

I am new to Razor Pages and looking for the best way to solve my problem.
Say I have an IndexModel class, that has some properties that rely on a DB context that is injected via the Constructer, such as a drop down list of Membership Levels, that comes directly from a table...
My question is what is the best way to handle populating this drop down list that I have for ALL requests that results in the same page being reloaded / returned. I know that I can put logic in OnGet to set up the list, the problem arises if say in OnPost, ModelState.IsValid is false, and so the page is returned with Page(). If I don't explicitly reinitialize the select list in OnPost, then I get a null reference exception, which is fair enough. Rewriting the code in the OnPost method goes against DRY principles, so I looked to writing a ConfirgureProperties() method in the class when needed.
Then by testing, I found that I can just set up a constructer that will take care of populating properties for me whenever they are needed, and I don't have to call anything else. Even when DI is involved, the injection is resolved at the top of the constructer, then I can use the context to do what I need for the other properties later in the constructer. I have seen no examples of this anywhere online, I only ever see people using constructers in page models that handle DI EXCLUSIVELY.
Is there a reason I SHOULD NOT be doing this, like bad coding practice or something, or is it ok for me to use page model constructers in this way?
Thanks
You only need to make the database call to repopulate the options in OnPost if ModelState is invalid. Chances are, if you have set up your validation correctly, that 99% of the time validation errors will be caught on the client and you won't need to repopulate the options.
Obtaining data from a database is costly, and you should only do it when necessary. So using the constructor approach contravenes this principal.
It's not like you are saving a lot of code either. Your ConfigureProperties method will only be called in two places in the PageModel.

Pass validation errors from service to controller

In my web app i have service layer responsible for all logic (like registering, etc.). I wanted to implement server-side validation for my forms. The thing is i can't just throw an exception every time i catch invalid data, because if user typed incorrect email AND password, my service method would just throw exception as soon as it checks email, and password error would be noticed only after user corrected email and resubmitted form. I want my entire form validated at once. The important thing is: i need only to pass error types, display messages must be added to ModelState in controller. I have some ideas and i would like you to help me decide which one is better from performance and good-practice point of view (maybe none - maybe there is another solution superior to all posted by me).
Ideas:
Collect errors in a dictionary and then throw single exception
containing all model errors in form of key-value (ex. "Password", "Must
be >5 signs"). In controller i catch error, and read all entries using switch() to detect error type and add proper message to ModelState.
Pros: uses built-in Exception.Data dictionary
Cons: need to decipher error type from the string
Similar to previous, but i create custom exception class, which has additional field-enum dictionary (ex. "Password", ValidationEnum.LessThanFiveSignsError).
Pros: Enums are more elegant solution for switch() operations
Cons: need to implement custom exception to do something that built-in exception class could do actually
Custom exception with dictionary, but with exceptions instead of enums - i create classes like StringTooShortException and UsernameAlreadyExistsException and add them to dictionary (ex. "Password", new StringTooShortException()). Switch would probably need to check type object...
Pros: i use exceptions? the more i think about it the more i believe this is not a good idea...
Cons: pass objects Exception subclass (with all Exception class attributes and stuff) and only use information of what type is that object?
Make my every service method return custom class containing {object regularReturnValueDependingOnMethod, MyCustomErrorContainer canBeListOfEnumsOrSomething}. Basic difference between this and previous ideas is that i don't throw an exception just to carry my error container up to controller, i use proper workflow.
Pros: doesn't throw exception, just returns validation errors to controller, uses proper workflow to pass values
Cons: isn't it too much to wrap return value of every method just to pass validation errors back to controller? maybe validation error is exactly the kind of situation, where i should use exception to carry a message to controller (whatever that message could be: a text string or, in this case, an entire object)
Don't wrap return value, just create validation error container in controller and pass it to service as "out" parameter
Pros: simple
Cons: need to create error container instance before calling any service method (ok, just ones which validate input). is it elegant?
What do you think? Which one is best? I'm not interested in just getting it done. I want to get it done the way it should be done. I want to learn good programming behavior :)
Thanks for any help :)
//edit:
My latest thought: I could create another service method just for validation purpose (ex. method: RegisterUser() for registration, and ValidateRegisterUser() for model validation, i would just have to make sure to call validation method before i call regular method. What do you think?

Getting attribute context in C#

Basically I'm trying to implement some sort of poor man's Aspect Oriented Programming in C#. I had thought about using a ContextAttribute but they seem only be be bound at the class level. Is there any way that I can put an attribute in such that it will receive the same parameters as the method which it annotates or some way to access the context in which it fired?
I have this code
public void AddUser(User user)
{
var errors = DataAnnotationsValidationRunner.GetErrors(user);
if (errors.Any())
throw new RulesException(errors);
users.Add(user);
}
from which I would like to extract the first 3 lines so I had something like
[Validated]
public void AddUser(User user)
{
users.Add(user);
}
I think you are missing a third component. Most AOP implementations (e.g. Aspect#) rely on a proxy or interceptor to actually execute the code. In your scenario, you lack whichever component needed to 1) know the attribute exists on the method, and 2) trigger the mechanism (or become it) needed to execute the code within the attribute.
Fortunately, there are already many (fairly) simple solutions available in open source. The simplest option I can think of would be to use a compile-time weaver like PostSharp. Grab a copy of that, and in the samples you'll find several examples of exactly what you are trying to do (you'd be interested in the OnMethodInvocationAspect).
The end result is that your code looks exactly like it does in the sample you provided, yet it's also running the code you wish.
Don't know exactly how your solution should look like, but in C# attributes do not execute code as long as you don't request them (as far as I know). And if you query for the attribute, you also have the context. So there is something wrong with your strategy in my opinion.

Categories