Hi I have db table which doesnot allow duplication of some column (ie. Name has to be unique). It seems, that current validation model can't handle this scenario well. I have created DTO with dependency on IMyRepository, but it hasn't been resolved. For now I decided to force DI using Abp.Dependency.IocManager.Instance.Resolve<IMyRepository>() but I don't like it. My proposition is to remove Validation feature from DTO and move it to external validation class, then inject. This gives a lot more flexibility in validation. Good validator :
- should be testable
- should be injectable
- should not pollute the class with attributes, since it makes class code less readable
- should be able to validate on server side and - if possible - for MVC
- should be able to provide/handle multiple validation scenarions for one class - very usefull when checking domain objects, not only DTOs I have used FluentValidation in my previous projects and have to say it works well. I believe it's not a big change - I could try to implement it on my own, but I'd like to know what do you think about it?
I think there are two types of validation:
Simply validating format of the DTO properties, like it should not be empty ([Required]), it should be maximum 10 chars ([MaxLEngth(10)])... and so on.. This can be easily done with data annotations and ICustomValide interface of ABP if needed.
Validating business rules that may require additional services (like repositories) and a part of business of the application. So, this should be done in a seperated class (that is used by application service by injecting). It may be called Policy or Strategy, like. For example: UserPolicy.CanCreateUserWithName(...) can check for duplication of the user name.
So, both of them have own power and own purpose. They can be used together.
Hikalkan, Thank you for the framework, and for forcing me to read more in this topic :) Your point of view is "MS way" (like described here: <a class="postlink" href="https://msdn.microsoft.com/en-us/library/ff649585.aspx">https://msdn.microsoft.com/en-us/library/ff649585.aspx</a>), mine is more "pragmatic". For me object is valid or not - only two states. The "Simple Validation" is some gray between black and white. Even if the validation method returns true, you can never be sure if the object is truly valid. Even simpliest models need some more sophisticated validation (like name uniqueness etc.), so almost always validation logic has to be splitted into "simple" and "advanced", without clear border which one is which. For me it's a mess not benefit. Are you sure, it's good design choice?
Yes, my approach is the MS way since we're coding in MS world :)
You're freely to use libraries like fluent validation and create a dedicated validator class for each DTO. This is found tedious by many developers like me. Because, many times DTOs have just simple validation and can be done using data annotations (like models in ASP.NET MVC). So, if I don't allow using data annotations, many developers will find the framework hard to work with. Even many developer can not understand purpose of DTOs well.
So, I choice to be elastic in this area. If you want, don't use data annotations and use validator classes. For me, I use data annotations (and ICustomValidate interface when needed). Most of times it solve the problem. If not, say I should check user name uniqueness, I do it in domain layer. Also, for this example, I think it's not good to check username uniqueness per DTO. It's business layer task and should be independed of any application method or DTO.