Closed TwentyFourMinutes closed 3 years ago
Hi @TwentyFourMinutes, thank you for your post.
I've been thinking about it a lot and still not fully convinced if we need a full, separate and independent nuget package just to wrap this use case. My only concern is that the functionality you described (automatic IoC registration) could be wrapped literally within a few lines of code. Let me sleep on it and I'll get back to this within a week, maybe with the solution draft.
PS. Regarding the objects that could be detected within the assembly, I think I already have something that meets your criteria: specification holders that can be combined with translation holders. What do you think?
Glad you are considering it. The specification holder is basically exactly what would be needed for this. If you want to lift some work over feel free to do so, I'd be more than happy to help out wherever I can.
Hey @TwentyFourMinutes , first of all - apologies for the terribly late reply. Over this exactly two months I've been covering other issues, including breaking changes that I plan to publish in version 2.0 just next month. Also, I had a plenty of time to think about this problem and ultimately ended up with the following solution:
FetchHolders
method that should be something you can use: Long story short: it's a function that scans the assemblies for ISpecificationHolder<T>
implementations and creates the helper objects that contain all information about these implementations (their type, type of the specification they keep, etc.). On top of this, it can create the validator out of the holder with merely a single, parameterless call. More information here, in the "Fetching holders" section.
Having that, the integration with DI container could be wrapped within few lines of code. Like this:
public static IServiceCollection AddValidators(this IServiceCollection @this, params Assembly[] assemblies)
{
var holders = Validator.Factory.FetchHolders(assemblies)
.GroupBy(h => h.SpecifiedType)
.Select(s => new
{
ValidatorType = s.First().ValidatorType,
ValidatorInstance = s.First().CreateValidator()
});
foreach (var holder in holders)
{
@this.AddSingleton(holder.ValidatorType, holder.ValidatorInstance);
}
return @this;
}
public void ConfigureServices(IServiceCollection services)
{
// ... registering other dependencies ...
services.AddValidators();
}
This is described with more details in the "Dependency injection" docs section.
FetchHolders
method, so you can call it and shape the results according to your specific needs (I imagine it's going to be few lines of LINQ statement at best).What do you think?
No worries about the late reply, people too often expect OS library maintainers to behave as someone who is getting paid for what they are doing, even if they are not. So shoutout to you for maintaining Validot ^^.
That being said, I appreciate the helper API and I am quite certain this is a totally viable options between both ideas. So from my side I am totally fine with that and the change is greatly appreciated.
My initial uncertainty came from the fact, that a lot of people might not be to familiar with Reflection and all its little quirks. Even though this is not the most beginner library. However with this and the documentation in place, I am pretty sure this won't be an issue.
@TwentyFourMinutes I believe for now the issue could be closed. I've just published version 2.0.0 (https://github.com/bartoszlenar/Validot/releases/tag/v2.0.0) and it already contains helpers for DI containers.
Tutorial how to use them is both in the project's readme and more details (including step-by-step guidance about implementing services.AddValidators()
method) is in the docs.
Looks good, thanks for the effort!
Feature description
As stated in the README:
I totally understand that and I agree with that, however as I am currently trying to replace FluentValidation with Validot I find it especially tedious to register all of those validators by hand and usually I use methods which automatically observe all the types/validators.
IMHO it is very important to keep things as simple as possible, in order to make a package as accessible as possible. This however, creates some kind of obstacle, at least to some degree. Especially due to the support for ASP.Net Core by FluentValidation.
To keep all worlds happy I'd suggest a second nuget package which helps solving that. On the one hand the core library is still totally independent and kept nice and tidy and on the other hand it is more user friendly.
Feature in action
Depending on the supported IOC Containers you would have something like the following.
Feature details
However this would raise the question, which kind of pattern would be used for this. I personally would have a few ideas, but would love to hear other ideas.
A static class containing all the validators
Pros It keeps things nice and tidy and you don't need to create a mess with dozen of classes. Cons As I am coming from a DDD background I strongly dislike this approach since a lot of these validators wouldn't belong in one class. Additionally this would be hard to observe and still would require some kind of naming convention or similar.
Classes with properties enforced through interfaces
Pros It would be more DDD conform and it would be way easier to observe with reflection. Cons This would obviously force the user to create a class for each validator which can lead to a lot of boilerplate.
Discussion
Now would you guys even be up to support/endorse something like that? Other implementation ideas?