valit-stack / valit Goto Github PK
View Code? Open in Web Editor NEWValit is dead simple validation for .NET Core. No more if-statements all around your code. Write nice and clean fluent validators instead!
License: MIT License
Valit is dead simple validation for .NET Core. No more if-statements all around your code. Write nice and clean fluent validators instead!
License: MIT License
Instead of having just one global namespace (Valit) @arekbal suggested to use it in a proper way, but all classes/extensions/enums etc. that are exposed to the user should be put inside "metadata" folder with its name staring with underscore (like _Valit). Thanks to that we'll be able to find all of the exposed classes inside the project (will be very handy even more when project will grow a lot).
Would be cool to create an integration package for Autofac. There are lot's of thing that we could add here so hesitate to add something in the comments ;) The simplest integration would be:
containerBuilder.RegisterValit();
Calling that we would look through the assembly and register all valitators as singletons.
Due to new architecture, we had to deprecate EnsureFor() in IValitRules. We need it back!
Add some basic tests for:
-Int16
-Int32
-Int64
-UInt16
-UInt32
-UInt64
-Single
-Double
-Byte
-Decimal
-Boolean
-String
Once we have CreateValitator()
extensions method introduced by NestedObjects PR, we can easily add same thing for IValitRules<TObject>
. This needs to be done after #120 PR will be merged.
WithStrategy and WithMessageKeyProvider should be optional to set
Default strategy should be set to Complete
This issue is related to the discussion started in #151 . Basically @tdeschryver suggested removing IValitRulesProvider
since it's not used for nested objects validation anymore. Then instead of doing:
ValitRules<Model>
.Create(provider.GetRules())
we could simply pass another IValitRules
object instead:
ValitRules<Model>
.Create(anotherValitRules)
This would also remove the confusion about the GetRules()
method since it's not clear whether it returnes IValitRules
or collection of IValitRule
. Looking forward for your opinion on that one :)
We should consider validation for Infinity in double and float. It might be tricky and honestly I don't know how how rules are implemented in C#. It's not super important imho.
Tests needed for:
As you can see, I added support for collections using EnureFor()
method (PR #120). The issue I noticed is related to the tagging.
The whole concept of supporting collection for either primitive types or nested objects is based on separated implementations of IValitRule<TObject, TProperty>
interface, so:
NestedObjectCollectionValitRule
CollectionValitRule
The idea was to aggregate all rules for collections using just one class. Why? Simply because at the point of doing EnsureFor()
we don't have the actual object hence we can't invoke the selector and iterate over the collectiom. So, it's a little bit like "lazy evaluation" when Validate()
method is called an the object is passed to this method. The issue I have is that user may tag the rules inside EnsureFor()
like in the example below:
...
.EnsureFor(m => m.Emails, _=>_
.Required().Tag("A")
.Email().Tag("B"))
But as I wrote, all these rules inside this method are evaluated during the validation. Therefore if user would do something like:
...
.EnsureFor(m => m.Emails, _=>_
.Required().Tag("A")
.Email().Tag("B"))
.GetTaggedRules()
He wouldn't get any result, because what was actually stored inside IEnumerable<IValitRule<TObject>>
was the instance of CollectionValitRule
which was not tagged by the user.
What really sucks is that actually I have no idea what behavior is correct in this particular scenario. Is this a bug or a feature? :D We need to discuss it until my PR will be merged.
Currently When()
takes Func<bool>
as the param but as we switched to IValitRule<TObject,TProperty>
we can change it to Predicate<TObject>
.
We should support validation for nested objects. As we discussed couple weeks ago we could provide a generic interface for our validator class like:
public interface IValitator<in TObject>
{
IValitResult Validate(TObject @object, IValit strategy strategy = null);
}
And then create an overload on the Ensure()
method which could get the instance of this validator instead of rules set:
...
.Ensure(m => m.NestedModel, new NestedModelValidator())
I'm still not quite convinced about an overload, maybe some extension method like:
.Ensure(m => m.NestedModel, _=>_
.WithValitator(new NestedModelValidator))
It's worth mentioning that the reason for putting strategy as a validator parameter is that doing this we can propagate chosen strategy (in the "root object") to the nested ones.
What are your thoughts about that guys?
We need testes for:
Requested coverage is 100%
Something weird happend to develop :/ Today I merged develop into master (with rebase) to create a release for version v0.2.0. After a while I realized that I forgot to change the version inside csproj file. I did the change on the develop and I created another PR from develop into master. It turned out that the PR contained all commmits (38) and changes (213) from from 0.2.0 once again. I updated the develop using the UPDATE button and... poof...
PR shown correct change (so just one change inside csproj) but develop has now duplicated commits from 0.2.0... I have no idea what happened! Now comes the best part. I didn't want to have a mess inside master so I squashed all these changes into one commit and merged it into master. So great, master has just one more commit since 0.2.0 merge with updated csproj. I wanted to test what would happend if I'll do some change on the develop once again. I did small change in the README, created new PR from develop to into master and... same story... I contains all commits and changes from 0.2.0... Do you have any idea what caused that? What options we have to fix that. The only one I have is to create new develop from master (tested that and worked as expected).
I'm sorry guys, that's probably my fault... But I swear, I've never had simmilar issue before...
I think that having the very solid Core library, we should start thinking about some integration projects and here comes the first one. I thought about creating new NuGet for the ASP.NET Core apps. The idea is simple, allow folks to kick off the validation before we start processing the particular action in the MVC6 controller, so the could use ModelState
object to see the result (just like it was achieved before using the attributes). So to me the whole process should look as follows:
Model
typeModelValitator
is created for typeStartup
we register of valitators autmatically using UseValit()
extensionpublic async Task DoSomethingAsync(Model model)
{
if(! ModelState.IsValid)
{
return BadRequest(ModelState.Errors);
}
....
}
That would be awesome ๐
E.g. for translation of the error messages depending on user's culture.
Basic usage would be something along the lines of
.WithMessage(()=> _translationService.GetError("Missing_Email"))
I noticed that we have very poor support for DateTime. We need couple methods which might be handy for people like:
I noticed that we still miss support for Guid type. If you have any suggestions about extension methods that could be useful, just write them below :) My thought was:
Currently to validate a nested object we need to pass the IValitRulesProvider
object to Ensure
method. Actually we could pass IValitator
object instead since there's no problem with that and we could simply a code even more. Honestly I don't why I didn't do this at the first time :D
I was dabbling around and noticed the Assert.Equal
methods in the tests are having the wrong signature.
For example:
Assert.Equal(result.Succeeded, expected);
should be:
Assert.Equal(expected, result.Succeeded);
Is it OK to change this (Assert.True
and Assert.False
) by using Shouldly
?
This way all our tests are written with Shouldly
.
Currently we don't support nullable types. Since they are very common we need overloads for most of our validation rules.
We should support adding message keys besides "classic" messages.
Tasks:
We need tests for integers:
-Int16
-Int32
-Int64
-UInt16
-UInt32
-UInt64
and nullable integers:
-Int16?
-Int32?
-Int64?
-UInt16?
-UInt32?
-UInt64?
Ideally we will have two generic classes which will handle most cases and 12 inherited classes which will contain more specific checks
All methods starting from Is
like IsDigit
or IsLetter
from https://msdn.microsoft.com/en-us/library/system.char(v=vs.110).aspx
There are problems in ValitRuleExtensions which surfaced with my PR.
Methods: Required
, IsEqualTo
, IsGreaterThan
, IsLessThan
, MinLength
, MaxLength
, Matches
handle null improperly.
In Required
p.Equals(default(TProperty))
tries to handle default values such as int
equal 0
as incorrect 'unrequired' value which is a very specific case... and imho requires specific, strongly typed extensions. Such as _=>_.Id)(_=>_.IsPositive())
Inside IsEqualTo
Given x.prop = null
and y.prop = null
Object.Equals(x.prop, y.prop)
makes sense when comparing two objects for similarity without given context.
IMO, user - in case he wants to not let null
pass - should have to be more specific and add Required
to handle null
there.
Similarly with IsGreaterThan
.
When ordering int? it makes sense to make the value null as being lower than 4. What IMO we want from user is to - again - be explicit about handling null
with Required
on Nullable
types or additional param.
And I dont like the way we oversimplify handling of these numbers... (separate overloads in separate namespaces?) float
s and double
s can be NaN
...
Also, Methods MinLength
, Maxlength
and Matches
could handle these string-like types safer and without typeof
with a string copy from IEnumerable<char>
such as new string(p.ToArray())
.
For plain strings I would suggest separate overload in separate namespace.
For instance:
public static class ValitRuleStringExtensions { public static IValitRule<TObject, string> MinLength<TObject>(this IValitRule<TObject, string> rule, int length) where TObject : class { rule.ThrowIfNull(ValitExceptionMessages.NullRule); return rule.Satisfies(p => p.Length >= length); } }
there is no magic or casts about it... ;)
Classes with very specific overloads for all the basic types. Drop the typeof
where possible...
So again I am not sure if these string validation extensions should require themselves input to not be null
...
So the question is:
.Required("missing value, Dude").MaxLength(5, "Input Value '{0}' is longer than {1}")
.MaxLength(5, "Input Value '{0}' is longer than {1} or maybe null?!?")
.MaxLength(5, "Input Value '{0}' is longer than {1}")
.Required().MaxLength(5, "Input Value '{0}' is longer than {1}")
Required
gets some default message customisable in "context" configuration.Currently we don't have any summary for classes and methods as well. As far as I know, this is highly requested by folks who could probably use Valit.
I'd be cool if we could add more things for customising error messages. I thought about something very simple like "tokens" which we could put into the string which then would be replaced with something like "{displayName} is required". I thought about the following tokens:
The above would imply adding new extension method - WithDisplayName()
๐ all,
Would it make sense to add a String.Required
rule, or should String.MinLength
be used here?
This rule would do the check via string.IsNullOrWhiteSpace()
.
I can create a PR if this gets expected.
Hi,
First of, great project here (found it via c# digest)!
After contributing yesterday, I would suggest these small changes - I'm willing to create PRs for the ones that get accepted ๐
.gitignore
because right now every file from ./tools
will be commited when someone builds the project via the build scriptsdotnet watch test
.editorconfig
.gitattributes
?We should support putting error codes besides "classic" messages.
Tasks:
Obvious ones are:
Currently we don't support Epsilon in extensions for double and float. The suggestion is that each method should have default parameter like:
(this IValitRule<TObject, double> rule, double value, double epsilon = 0.0d)
so user can specify it, but it's not required. Each method should then consider this number in the calculations. Need to applied for:
Version 0.2.0 was released two days ago, o I think we can start thinking about features for next release. If you have any suggestions, please put them in the comments below :)
For a now we'll definitely, add:
Since For(TObject @object)
is static initialize method, we have to pass the object even if we just want to execute set of rules.
Tasks:
IValitRules<TObject>
IEnumerable<IValitRule<TObject>>
Does anyone could help me with docs for next release? PLEASE!
We need to add:
Inside "Validation rules"
Required()
for string in "Available validation rules"We also need to add new page called "Valitators" and describe how to create them from:
IValitRulesProvider<TObject>
IValitRules<TObject>
There are - in .net - basic built in validation components, which our validation system should support in some later versions. Most of them are placed in assembly+namespace: System.ComponentModel.DataAnnotations
MaxLengthAttribute and so on...
Currently we have 3 places where the code responsible for getting the result from rules is duplicated:
ValitRules
NestedObjectValitRule
NestedObjectCollectionValitRule
Would be cool if we could get rid of this somehow ๐
I think it could be nice to have ability to compare two properties of an object:
.Ensure(m => m.Password, _ => _.IsEqualTo(m => m.RePassword))
What do you think about it?
Currently we can do something like this:
....
.Ensure(model => model.IntValue)
.Required()
...
The problem with the above approach is that we use default(TProperty)
inside the condition. Due to that fact if IntValue equals 0, Required rule is not satisfied. We should change that. The suggested solutions are:
Required
which takes a "strategy" how 0 should be treated.IsPositive()
and .IsNegative()
methods.IsNonDefault()
I'm open for more suggestions on that one guys ;)
Guys, I'd like to add AUTHORS.txt file inside the project so folks can see the full list of contributors + their emails to contact. If you don't mind, please give me your emails that you'd like to put inside.
We need to test:
I think it would be nice to have a default messages for all validation rules. Notice that in most cases you would write message like:
.Ensure(m => m.IntValue, _=>_
.IsGreaterThan(2)
.WithMessage("IntValue is not greater than 2"))
... and so on. What I'm trying to say is that in many cases the actual message would be quite predictable :D That's why I thought about populating the ErrorMessages
array in the IValitResult
with default messages. Of course using WithMessage()
would replace that with the custom one. I guess that, this feature wouldn't work with the Error Codes because eveybody has completely different system for doing that.
We should support adding tags, so we can group and validate specific set of rules.
Tasks:
Nice to have:
As you see we have a #114 almost done by @paw3lx. However we spotted that this feature requires the whole rules chain to be resolved inside Validate()
method since the object is required as a one of the parameter of the selector. This will cause the inconsistency comparing to the previous solution where each chain is resolved inside ValitRules
object (more precisely inside Ensure()
). Now we have two options:
Validate()
method to be consistentA declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.