I've been calling my services using HostContext.ResolveService() but realized that none of my FluentValidations are being called for my request object. Doing a quick search I saw a workaround was to call the JsonServiceClient version but that would mean I'm doing full http overhead to call an internal c# service.
If I use the JsonServiceClient Send instead of the Post version the validation is also not called.
Am I missing something simple or do I need to explicitly call the validator.validate?
What is the proper approach?
If you use
ExecuteMessage the fluent validator will be called:
HostContext.ServiceController.ExecuteMessage(new Message<T>(requestDto), httpReq);
See StackOverflow for more details.
However, I'd suggest that if you are making an in-process request, the request should be valid (meaning it shouldn't need to be validated). The filters for authentication and validation are skipped because these are for external un-trusted inputs. I'm assuming that you need to validate the request as its values come from user input. You are best validating user input at the point it enters the system (i.e. before calling the service in this case). This probably means some of the validation logic will be duplicated in the client (code that is calling the service) using the appropriate technology (for example MVC Data Annotation Attributes). You could re-use the fluent validators in your UI layer (like you suggest), though you'd need to map the view-model to the request DTO, validate and then map any errors back to your view-model (presuming the request DTO and view-model are not the same). The complexity of your validation logic will probably dictate the best implementation (e.g. duplication vs mapping).
Thank you for the quick reply George.
You are correct in your assumption that the values are coming from user input and as such cannot be trusted. I've taken more of a microservice approach and hence ended up down this path. As an example I might have an image service to upload media that performs validation around file format, height and width as a contrived example. This service is used as part of multiple workflows to change a user's thumbnail or by a picture gallery to upload images etc... The service could be consumed directly by the user in the thumbnail example or as part of a larger multistep user registration workflow and thus called internally by the registration service.
You answer was quite helpful and I appreciate it. This allows me to choose the approach that fits the best.
Now I have the fun of figuring out how to handle transactions/rollback across multiple services:(
I'm glad it was helpful. A few further thoughts on this:
Validating close to the data input enables context specific validation criteria. In your example the core image service may be able to handle images of infinite size, however when setting a thumbnail (a different service) you may wish to restrict the size. The context specific criteria will need to be at least as strict as what can be handled, but it does give you more options.
if you don't want context specific validation I think either reusing the fluent validator or treating the service as an external system (but without the HTTP overhead) using
ExecuteMessage is a reasonable approach.