Nested validators can only be used with Member Expressions - validation

I am trying to use fluent validation .
Looking to run validation against the IList items.
public class ProgramDetailsValidatorForBulkEdit : ValidatorCollection<IList<ProgramDTO>>
{
public ProgramDetailsValidatorForBulkEdit()
{
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure).SetCollectionValidator(new ProgramDetailsValidator1());
}
}
public class ProgramDetailsValidator1 : AbstractValidator<ProgramDTO>
{
public ProgramDetailsValidator1()
{
RuleFor(c => c.Capacity).NotNull()
.WithMessage(String.Format(AppConstants.ValidationTemplates.RequiredField, "Capacity"));
}
}
The error returned when calling the line is "Nested validators can only be used with Member Expressions."
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure).SetCollectionValidator(new ProgramDetailsValidator1());

Reason of error
Error message contains words "Member Expressions". The problem is in RuleFor(x => x). Nested validators must be used only with lambdas which select some members of x, for example, with x => x.MySubobject1. Lambda x => x does not select any member of x.
To validate the collection
Create object containing the list:
public class MyObject
{
public List<Item> Items { get; set; }
}
You can use generics to create 1 universal object and validator for it for all lists.
public class MyObjectValidator : AbstractValidator<MyObject>
{
public MyObjectValidator()
{
RuleFor(x => x.Items) // will work, because it is not "x => x"
.SetCollectionValidator(new ItemValidator());
}
}
To validate an object
Use lambdas pointing to members to validate inner objects and use inheritance from your object's validator to validate the root x.
public class MySimpleObject { ... }
public class MyCompositeObject : MySimpleObject
{
public MyType1 MySubobject1 { get; set; }
public MyType2 MySubobject2 { get; set; }
}
public class MySimpleObjectValidator : AbstractValidator<MySimpleObject>
{
public MySimpleObjectValidator()
{
...
}
}
public class MyCompositeObjectValidator : MySimpleObjectValidator
{
public MyCompositeObjectValidator () : base() // Call base validator to implement rules for "x => x" written in MySimpleObjectValidator!
{
// Rules for SUBobjects will work
RuleFor(x => x.MySubobject1)
.SetValidator(new MyType1Validator())
.WithName("Subobject1's errors group");
RuleFor(x => x.MySubobject2)
.SetValidator(new MyType2Validator())
.WithName("Subobject2's errors group");
}
}

Related

GraphQL Generics Unexpected Value Type Error

I can't figure out how to make the GraphQL types happy with my Generics plan. I am trying to have a response wrapper for all my query and mutation definitions.
Everything was working fine with my query definition using PaginationType and my service returning the Pagination model and all was good. I added the ResponseType wrapper and now I get the conflict.
Expected value of type "ABC.GraphQL.Framework.DTO.ResponseType1[ABC.GraphQL.Framework.Types.Object.PaginationType]\" for \"ResponseType\" but got: ABC.GraphQL.Framework.DTO.Response1[ABC.GraphQL.Framework.DTO.Pagination].",
FieldAsync<ResponseType<PaginationType>>(
"PaginationSearch",
"Returns paginated groups for specified search terms",
arguments: new QueryArguments(...),
resolve: async context => {
return await Service.GetPagination(...);
}
);
public class PaginationType : ObjectGraphType<Pagination>
{
public PaginationType()
{
Field(x => x.totalRecords, nullable: true).Description("Total Records");
....
}
}
public class ResponseType<T> : ObjectGraphType<Response<T>>
{
public ResponseType()
{
Name = "ResponseType";
Field(x => x.success, nullable: true).Description("Operation Success");
Field(x => x.message, nullable: true).Description("Operation Message");
Field(x => x.response, nullable: true, typeof(T)).Description("Operation Response");
}
}
Of course the plain backing models
public class Pagination
{
public int totalRecords { get; set; }
.....
}
public class Response<T>
{
public bool success { get; set; }
public string message { get; set; }
public T response { get; set; }
}
Now my service class returns the plain objects and this has been working to this point so not sure why adding the Response wrapper is now breaking it.
public async Task<Response<Pagination>> GetPagination(...)
{...}
I debugged into the GraphQL library and found it is by design. So I begun digging into to why and found this:
https://github.com/graphql-dotnet/graphql-dotnet/issues/2279

Exclude particular property from validation. FluentValidation

I have a class with complex property:
public class A{
public B Property{ get; set; }
}
public class B{
public string Name{ get; set; }
}
In some cases I'm using only B type, in others A type. But I want to validate B type itself but NOT validate B type as part of A class.
I wrote those validators:
public class BValidator : AbstractValidator<B>
{
public BValidator()
{
RuleFor(x => x.Name).NotEmpty();
}
}
public class AValidator : AbstractValidator<A>
{
public BValidator()
{
RuleFor(x => x.A).Configure(x => x.ClearValidators());
}
}
And it works inside my views. But when I post A class with empty B.Name the ModelState is not valid. Is it the way to make ModelState valid?
"B" "a part of A" is not going to run unless you tell it to.
B validation as a part of A........is only going to happen if you ask it to.
Below I've made "B as a part of A" as optional, via a bool flag to demonstrate.
public class AValidator : AbstractValidator<A>
{
public AValidator (bool includeBasAPartOfA)
{
if(includeBasAPartOfA)
{
RuleFor(x => x.Property).SetValidator(new BValidator());
}
}
}

Linq expression where clause with generic type

In my Data access layer, I am calling the GET method with the following Lambda expression :
public List<T> Get<T>() where T : class
{
var list = Context.Set<T>().ToList().Distinct().Where(x => x.Content_type == "Test");
return list;
}
But getting error
"Cannot resolve symbol Content_type"
How can i resolve this issue ?
The problem is that Content_type is not a part of T class because it's just a class.
As #tchelidze says, you can set a where clause on your function to specify a type, like this :
public List<T> Get<T>() where T : IYourCommonInterface
{
var list = Context.Set<T>().Where(x => x.Content_type == "Test").Distinct().ToList();
return list;
}
But if you need to be totaly generic, you can add a selector to your function like this :
public List<T> Get<T>(Func<T, object> selector) where T : class
{
var list = Context.Set<T>().Where(x => selector(x) == "Test").Distinct().ToList();
return list;
}
And use it like that :
Get(x => x.Content_type);
Also, if you want to go further, you can pass the entire condition :
public List<T> Get<T>(Func<T, bool> condition) where T : class
{
var list = Context.Set<T>().Where(condition).Distinct().ToList();
return list;
}
And use it like this :
Get(x => x.Content_type == "test");
Hope it helps.
Reason is that all you know about T is that it is a class. You do not know if it contains Content_type property or not.
If you always pass T class which contains definition for Content_type try following .
Context.Set<T>().ToList().Distinct().Where(x => (x as SomeClassWithContentTypeField).Content_type == "Test");
Better way will be if you introduce interface IHasContentTypeField which declared Content_type property
public interface IHasContentTypeField
{
string Content_type { get; set; }
}
then constraint T to this interface.
public List<T> Get<T>() where T : IHasContentTypeField
Then you can implement IHasContentTypeField in classes for which you want to call Get<T> method.
public class A : IHasContentTypeField
{
public string Content_type { get; set; }
}

How to unit test child validators with When() condition with FluentValidation.TestHelper

The extension method .ShouldHaveChildValidator() in the FluentValidation.TestHelper namespace doesn't have an overload that takes the model. How do I then test that the child validators are set up correctly when using a When() clause like in the following example?
E.g.
public class ParentModel
{
public bool SomeCheckbox { get; set; }
public ChildModel SomeProperty { get; set; }
}
public class ParentModelValidator : AbstractValidator<ParentModel>
{
RuleFor(m => m.SomeProperty)
.SetValidator(new ChildModelValidator())
.When(m => m.SomeCheckbox);
}
I want to Assert that if SomeCheckbox is true, then the child validator is present, and if SomeCheckbox is false, then the child validator isn't present.
I have the following so far in the unit test:
ParentModelValidator validator = new ParentModelValidator();
validator.ShouldHaveChildValidator(
m => m.SomeProperty,
typeof(ChildModelValidator));
but that doesn't take into account the .When() condition.
I notice other methods in the FluentValidation.TestHelper namespace such as .ShouldHaveValidationErrorFor() have an overload that takes the model, so it's easy to test a simple property type with a When() clause by setting up a model that satisfies the precondition.
Any ideas?
Here's a snippet of how I achieve this:
public class ParentModelSimpleValidator : AbstractValidator<ParentModel>
{
public ParentModelSimpleValidator()
{
When(x => x.HasChild, () =>
RuleFor(x => x.Child)
.SetValidator(new ChildModelSimpleValidator()));
}
}
public class ChildModelSimpleValidator : AbstractValidator<ChildModel>
{
public ChildModelSimpleValidator()
{
RuleFor(x => x.ChildName)
.NotEmpty()
.WithMessage("Whatever");
}
}
Here's the relevant simplified models:
[Validator(typeof(ParentModelSimpleValidator))]
public class ParentModel
{
public bool HasChild { get { return Child != null; } }
public ChildModel Child { get; set; }
}
[Validator(typeof(ChildModelSimpleValidator))]
public class ChildModel
{
public string ChildName { get; set; }
public int? ChildAge { get; set; }
}
Here's a sample unit test:
[TestMethod]
public void ShouldValidateChildIfParentHasChild()
{
var validator = new ParentModelSimpleValidator();
var model = new ParentModel
{
ParentName = "AABBC",
Child = new ChildModel { ChildName = string.Empty }
};
validator.ShouldHaveErrorMessage(model, "Whatever");
}
very late to the game here, but I just started using FluentValidation and that was my solution
public class ParentValidator: AbstractValidator<ParentModel>
{
public ParentValidator()
{
// other rules here
// use == for bool?
When(model => model.SomeBoolProperty == false, () => RuleFor(model => model.ChildClass).SetValidator(new ChildClassValidator()));
}
}
public class ChildClassValidator: AbstractValidator<ChildClass>
{
public ChildClassValidator()
{
this
.RuleFor(model => model.SomeProperty).NotNull();
}
}
then the test is
[TestMethod]
public void ParentValidator_should_have_error_in_child_class_property_when_bool_is_false_on_parent()
{
// Arrange - API does not support typical unit test
var validator = new ParentValidator()
var foo = new ParentModel() { SomeBoolProperty = false };
foo.ChildClass.SomeProperty = null;
// Act
var result = validator.Validate(foo);
// Assert - using FluentAssertions
result.Errors.Should().Contain(err => err.PropertyName == "ChildClass.SomeProperty");
}

Linq - reuse expression on child property

Not sure if what I am trying is possible or not, but I'd like to reuse a linq expression on an objects parent property.
With the given classes:
class Parent {
int Id { get; set; }
IList<Child> Children { get; set; }
string Name { get; set; }
}
class Child{
int Id { get; set; }
Parent Dad { get; set; }
string Name { get; set; }
}
If i then have a helper
Expression<Func<Parent,bool> ParentQuery() {
Expression<Func<Parent,bool> q = p => p.Name=="foo";
}
I then want to use this when querying data out for a child, along the lines of:
using(var context=new Entities.Context) {
var data=context.Child.Where(c => c.Name=="bar"
&& c.Dad.Where(ParentQuery));
}
I know I can do that on child collections:
using(var context=new Entities.Context) {
var data=context.Parent.Where(p => p.Name=="foo"
&& p.Childen.Where(childQuery));
}
but cant see any way to do this on a property that isnt a collection.
This is just a simplified example, actually the ParentQuery will be more complex and I want to avoid having this repeated in multiple places as rather than just having 2 layers I'll have closer to 5 or 6, but all of them will need to reference the parent query to ensure security.
If this isnt possible, my other thought was to somehow translate the ParentQuery expression to be of the given type so effectively:
p => p.Name=="foo";
turns into:
c => c.Dad.Name=="foo";
but using generics / some other form of query builder that allows this to retain the parent query and then just have to build a translator per child object that substitutes in the property route to the parent.
EDIT:
Following on from comments by #David morton
Initially that looks like I can just change from Expression to a delegate function and then call
.Where(ParentQuery()(c.Dad));
However I am using this in a wider repository pattern and cant see how I can use this with generics and predicate builders - I dont want to retrieve rows from the store and filter on the client (web server in this case). I have a generic get data method that takes in a base expression query. I then want to test to see if the supplied type implements ISecuredEntity and if it does append the securityQuery for the entity we are dealing with.
public static IList<T> GetData<T >(Expression<Func<T, bool>> query) {
IList<T> data=null;
var secQuery=RepositoryHelperers.GetScurityQuery<T>();
if(secQuery!=null) {
query.And(secQuery);
}
using(var context=new Entities.Context()) {
var d=context.GetGenericEntitySet<T>();
data=d.ToList();
}
return data;
}
ISecuredEntity:
public interface ISecuredEntity : IEntityBase {
Expression<Func<T, bool>> SecurityQuery<T>();
}
Example Entity:
public partial class ExampleEntity: ISecuredEntity {
public Expression<Func<T, bool>> SecurityQuery<T>() {
//get specific type expression and make generic
Type genType = typeof(Func<,>).MakeGenericType(typeof(ExampleEntity), typeof(bool));
var q = this.SecurityQuery(user);
return (Expression<Func<T, bool>>)Expression.Lambda(genType, q.Body, q.Parameters);
}
public Expression<Func<ExampleEntity, bool>> SecurityQuery() {
return e => e.OwnerId==currentUser.Id;
}
}
and repositoryHelpers:
internal static partial class RepositoryHelpers {
internal static Expression<Func<T, bool>> SecureQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>();
}
return null;
}
}
EDIT Here is the (eventual) solution
I ended up going back to using expressions, and using LinqKit Invoke. Note: for EF I also had to call .AsExpandable() on the entitySet
The key part is being able to call:
Product.SecureFunction(user).Invoke(pd.ParentProduct);
so that I can pass in the context into my parent query
My end classes look like:
public interface ISecureEntity {
Func<T,bool> SecureFunction<T>(UserAccount user);
}
public class Product : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Expression<Func<Product,bool>> SecureFunction(UserAccount user) {
return f => f.OwnerId==user.AccountId;
}
public string Name { get;set; }
public string OwnerId { get;set; }
}
public class ProductDetail : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
return pd => Product.SecureFunction(user).Invoke(pd.ParentProduct);
}
public int DetailId { get;set; }
public string DetailText { get;set; }
public Product ParentProduct { get;set; }
}
Usage:
public IList<T> GetData<T>() {
IList<T> data=null;
Expression<Func<T,bool>> query=GetSecurityQuery<T>();
using(var context=new Context()) {
var d=context.GetGenericEntitySet<T>().Where(query);
data=d.ToList();
}
return data;
}
private Expression<Func<T,bool>> GetSecurityQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
}
return a => true; //returning a dummy query
}
}
Thanks for the help all.
You're overthinking it.
First, don't return an Expression<Func<Parent, bool>>, that'll require you to compile the expression. Return simply a Func<Parent, bool> instead.
Next, it's all in how you call it:
context.Children.Where(c => c.Name == "bar" && ParentQuery()(c.Dad));
context.Parents.Where(ParentQuery());

Resources