Quantcast
Channel: Fluent Validation for .NET
Viewing all 1917 articles
Browse latest View live

New Post: Checking for Immutable property changes

$
0
0
Hi and thanks for your reply.

I'm just about to trawl the source code looking to implement a custom rule. I assume at some point you check the member expression for the name, you did something similar in your SagePayMvc project (thanks for that btw! argh sagepay) when getting config values. So I should be able to access this value like the custom message right?

Unless there's some reason why I wouldn't be able to do this off the top of your head before I start?

New Post: Checking for Immutable property changes

$
0
0
Actually I think I've found what I need with the code below and the examples of the Validators. Thanks again.
               public static IRuleBuilderOptions<T, TProperty> Must<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder,
                                                                           Func<TProperty, bool> predicate) {
            predicate.Guard("Cannot pass a null predicate to Must.");

            return ruleBuilder.Must((x, val) => predicate(val));
        }

               public static IRuleBuilderOptions<T, TProperty> Equal<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression, IEqualityComparer comparer = null) {
            var func = expression.Compile();
            return ruleBuilder.SetValidator(new EqualValidator(func.CoerceToNonGeneric(), __expression.GetMember()__, comparer));
        }

                 /// <summary>
        /// Gets a MemberInfo from a member expression.
        /// </summary>
        public static MemberInfo GetMember<T, TProperty>(this Expression<Func<T, TProperty>> expression) {
            var memberExp = RemoveUnary(expression.Body);

            if (memberExp == null) {
                return null;
            }

            return memberExp.Member;
        }

        private static MemberExpression RemoveUnary(Expression toUnwrap) {
            if (toUnwrap is UnaryExpression) {
                return ((UnaryExpression)toUnwrap).Operand as MemberExpression;
            }

            return toUnwrap as MemberExpression;
        }

New Post: Checking for Immutable property changes

$
0
0
If anyones interested here's an example
public static IRuleBuilderOptions<T, TProperty> NotIllegallyModified<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, DbDataRecord originalValues, bool allowNullInstantiation)
        {
            return ruleBuilder.SetValidator(new IllegallyModifiedValidator(originalValues, allowNullInstantiation));
        }

public class IllegallyModifiedValidator : PropertyValidator
    {
        public DbDataRecord originalValues { get; private set; }
        public bool allowNullInstantiation { get; private set; }

        public IllegallyModifiedValidator(DbDataRecord originalValues, bool allowNullInstantiation): base("Property has been illegally modified")
        {
            this.originalValues = originalValues;
        }

        protected override bool IsValid(PropertyValidatorContext context)
        {
            var originalValue = originalValues.GetValue(originalValues.GetOrdinal(context.PropertyName));
            if (originalValue != null || (originalValue == null && !allowNullInstantiation))
            {
                if (!originalValue.Equals(context.PropertyValue)) return false;
            }
            return true;
        }
    }

 public class BatchValidator : AbstractValidator<Batch>
    {
        public BatchValidator(ObjectStateEntry entry)
        {
               // Some stuff
            switch (entry.State)
            {
                case EntityState.Added:
                    RuleFor(r => r.Code).Must(x => IsCodeUnique(x)).WithMessage("Batch code has already been used");
                    break;
                case EntityState.Modified:
                    var originalValues = entry.OriginalValues;
                    RuleFor(r => r.Code).NotIllegallyModified(originalValues, false).WithMessage("Batch Code may not be modified after creation. Batch must be recalled.");
                    RuleFor(r => r.Code).NotIllegallyModified(originalValues, false).WithMessage("Expiry date cannot be modified after creation.  Batch must be recalled.");
                    break;
            }
        }
    }

New Post: MVC client-side and server-side collection validation

$
0
0
[Validator(typeof(SaveModelValidator))]
public class SaveModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool UseDateRanges { get; set; }
    public ICollection<PeriodModel> Periods { get; set; }
}

// Without this attribute no unobtrusive attributes are rendered
// BUT
// With this attribute PeriodModel is validate server side even if
// SaveModelValidator does not have the second rule (the one on Periods)
//
// This happens even if I do not use When and I do not know how to validate
// what I want both client side and server side: if I could write a C# attribute
// to only allow client side unobtrusive attributes rendering and not server
// side validation it would be fine.
[Validator(typeof(PeriodModelValidator))]
public class PeriodModel
{
    public int Id { get; set; }
    public DateTime? Start { get; set; }
    public DateTime? End { get; set; }
}



public class SaveModelValidator : AbstractValidator<SaveModel>
{
    public SaveModelValidator()
    {
        RuleFor(x => x.Name)
            .NotEmpty().WithName("InternalName")
            .Length(4, 150).WithName("InternalName");

        RuleFor(x => x.Periods)
            .NotEmpty().When(x => x.UseDateRanges).WithName("Periods")
            .SetCollectionValidator(new PeriodModelValidator()).When(x => x.UseDateRanges).WithName("Periods");
    }
}

public class PeriodModelValidator : AbstractValidator<PeriodModel>
{
    public PeriodModelValidator()
    {
        RuleFor(x => x.Start)
            .NotEmpty().WithName("PeriodStart");

        RuleFor(x => x.End)
            .NotEmpty().WithName("PeriodEnd")
            .GreaterThanOrEqualTo(x => x.Start).WithName("PeriodEnd");
    }
}

New Post: FV and IoC

$
0
0
Hi Thi517, can you tell me where the static container function and the internal class FluentValidatorModule live in code?
(Where are they to be defined? In which files?)

And what is SiteModule() used for?

I have not yet seen a working example anywhere on Ninject with FluentValidation- for some reason, every example I see comes up just short of piecing it all together, but yours is the closest. For some reason a Fluent+Ninject working example is very, very elusive. Surely someone must have done it by now.

New Post: Mulitple Withs on One Property

$
0
0
Forgive me if this has been addressed, but I wasn't able to find a solution to this issue.

I have a Contact Object that has a ContactType & the Value. For simplicity, the ContactType can be either Phone or Email. Here is my Class:
    public class Contact
    {
        public int ContactType { get; set; }
        public string Value { get; set; }
    }

    public enum ContactType
    {
        Phone = 1,
        Email = 2
    }
My intention is to create a validator that has this logic:
1) If the Contact Type is 1 (Phone), use a Regular Expression to Validate that it is a valid phone number.
2) If the Contact Type is 2 (Email), use the EmailAddress() method to Validate that it is a valid Email Address.

Here is the Validator that I thought would work:
public ContactValidator()
{
    RuleFor(x => x.Value).EmailAddress().When(x => x.ContactType == (int)ContactType.Email)
                         .Matches(@"^\d{3}(\-| )?\d{3}(\-| )?\d{4}$").When(x => x.ContactType == (int)ContactType.Phone)
                         .NotEmpty();
}
When it runs, if the ContactType is 1 (Phone), the validator works, and it gives me the error message, but if the ContactType is 2, it never gives a validation error, even if the Value is not a valid Email Address.
When I run the Contact Type validation separately (removing either the Phone or Email validation from the RuleFor), each one works. Can anyone point me in the right direction in how to accomplish this?

Thanks in advance for any help.

New Post: Shortcut for validating variable length list with unordered indexer

$
0
0
I'm looking for a solution for a while and all solutions are hacky. All needs for variable length list with unordered indexer is change current CollectionValidator to:
  • adding access to collection within CollectionValidator
  • adding current index of item which is being validated
  • adding possibility to assign different indexer (indexer field from validated item)
I have no time to create full blown solution so I create next hacky solution but in nicer way.
For the rest of mvc code refer to this: http://ivanz.com/2011/06/16/editing-variable-length-reorderable-collections-in-asp-net-mvc-part-1/

Shortcut extension method
        public static IRuleBuilderOptions<T, IEnumerable<TProperty>> ValidateCollection<T, TProperty>(
            this IRuleBuilder<T, IEnumerable<TProperty>> ruleBuilder,
            Expression<Func<TProperty, object>> indexerProperty,
            Action<CollectionItemsValidator<T, TProperty>.Context> result)
        {
            return ruleBuilder.SetValidator(new CollectionItemsValidator<T, TProperty>(result, indexerProperty));
        }
Validator
    public class CollectionItemsValidator<T, TProperty> : NoopPropertyValidator
    {
        private readonly Action<Context> _result;
        private readonly Expression<Func<TProperty, object>> _indexerProperty;

        public CollectionItemsValidator(Action<Context> result, Expression<Func<TProperty, object>> indexerProperty)
        {
            _result = result;
            _indexerProperty = indexerProperty;
        }

        public override IEnumerable<ValidationFailure> Validate(PropertyValidatorContext context)
        {
            context.MessageFormatter.AppendPropertyName(context.PropertyDescription);

            var items = context.PropertyValue as IEnumerable<TProperty>;
            if (items == null) return null;
            var properties = items as TProperty[] ?? items.ToArray();
            if (!properties.Any()) return null;

            var ctx = new Context(context, _indexerProperty);
            int index = 0;
            foreach (var item in properties)
            {
                ctx.SetItem(item, index);
                _result(ctx);
                index = index + 1;
            }
            return ctx.Errors;
        }

        public class Context
        {
            private readonly PropertyValidatorContext _context;
            private readonly Func<TProperty, object> _indexerProperty;
            private readonly IList<ValidationFailure> _errors;

            public Context(PropertyValidatorContext context, Expression<Func<TProperty, object>> indexerProperty)
            {
                _context = context;
                _indexerProperty = indexerProperty.Compile();
                _errors = new List<ValidationFailure>();
                Model = (T)context.Instance;
            }

            public void AddError(Expression<Func<TProperty, object>> property, string message)
            {
                var propertyName = property.GetPath();
                var newChain = new PropertyChain(_context.ParentContext.PropertyChain);
                newChain.Add(_context.Rule.Member);
                newChain.AddIndexer(_indexerProperty(Item));
                newChain.Add(propertyName);
                _errors.Add(new ValidationFailure(newChain.ToString(), message));
            }

            public IEnumerable<ValidationFailure> Errors { get { return _errors; } }

            internal void SetItem(TProperty item, int index)
            {
                Item = item;
                ItemIndex = index;
            }

            public int ItemIndex { get; private set; }
            public TProperty Item { get; private set; }
            public T Model { get; private set; }
        }
    }
Usage example:

public class Model
{
    public IEnumerable<Point> Points {get;set;}
}

public class Point
{
    public string Index {get;set;}
    public DateTime? ReturnDepartureHour {get;set;}
}

RuleFor(x => x.Points).ValidateCollection(
    x => x.Index, // <- assign indexer
    c =>
    {
        if (c.ItemIndex != 0 && !c.Item.ReturnDepartureHour.HasValue) // validation ReturnDepartureHour but only if item is not at index zero
        {
            c.AddError(x => x.ReturnDepartureHour, "Row {0} - return deprature hour is required".Fmt(c.ItemIndex));
        }
    });
Feel free to comment/use :)

Regards
Darek

New Post: Mulitple Withs on One Property

$
0
0
Hi

When clauses apply to all previous validators in the same chain, so in this example the second When clause ends up running on both previous rules. You'll need to split it up into two rules:
RuleFor(x => x.Value).EmailAddress().When(x => x.ContactType == (int)ContactType.Email);
RuleFor(x => x.Value).Matches(@"^\d{3}(\-| )?\d{3}(\-| )?\d{4}$").When(x => x.ContactType == (int)ContactType.Phone);

New Post: MVC client-side and server-side collection validation

$
0
0
Hi

This isn't something that's supported I'm afraid. By putting the validator attribute on the PeriodModel, validation will always be invoked (as it's no longer tied to calling SetCollectionValidator). If you remove the ValidatorAttribute from the PeriodModel, then it will only be validated as part of the SetCollectionValidator call, but then you'll lose the client-side attributes.

I cannot currently think of a way of disconnecting the two - ASP.NET MVC's validation infrastructure is very inflexible (I seriously regret ever having written the MVC integration). Both generation of client-side rules and server-side validation run through the same pipeline. I'll have a play with it and see if I can hack something together, but I probably won't get a chance to do that until late next week.

Jeremy

New Post: Mulitple Withs on One Property

$
0
0
Thank you for your help. I thought I read somewhere that there can only be one rule for each property, which is why I was trying to get it all shoved into a single line of code.

And also, thank you for creating this and allowing us to use it for free. Not only does it work really well, it is extremely easy to use.

New Post: Mulitple Withs on One Property

$
0
0
Glad you're finding it useful! :)

New Post: MVC client-side and server-side collection validation

$
0
0
Thank you for you reply!

I explored your codebase and unless ShouldGenerateClientSideRules return false when SetCollectionValidator is called I could not understand what prevents a non attribute created validator from generating unobtrusive html attributes...

Anyway wouldn't it be possible to define an attribute, say ClientValidator, so that we can use it only to generate unobtrusive html attributes, leaving Validator classes in control of server side validation?

New Comment on "Customising"

$
0
0
Could you please clarify in the paragraph about CascadeMode that no matter where the CascadeMode is defined, it will always only have effect within a rule fefinition. Even when StopOnFirstFailure is defined for the whole validator, other rules will be evaluated when an error is found in a previous rule. That just cost me quite some time to figure out.

New Post: Dynamic Form Fields

$
0
0
@Jeremy
I test your code. it works good . but the problem is we lost client validetion.

in fact i have
 public class FieldViewModel
    {
        public string FieldName { get; set; }
        public string FieldValue { get; set; }
        public List<int> Validations { get; set; } // list of validation must applied to FieldValue for example : 1 required , 2 Email , ... 
     
    }
I feel FieldName and Validations of FieldViewModel from database
I want to have both Client and Server side validation for FieldValue
how can do this?

New Post: Dynamic Form Fields

$
0
0
Hi

This isn't possible I'm afraid - this code is server-side only.

New Post: Dynamic Form Fields

$
0
0
I've solved my issue by inject all attributes that jQuery.Unobtrusive.Validation needs manually
I think this can be integrated by fluent validation in next version!
All reseon i've used fluent validation because of dynamic validation for making form builder

New Post: WithLocalizedMessage overload with instance of type being validated?

$
0
0
Hi Jeremy,

I'm afraid of writing about this issue once again here but beleve me, I think I tried everything but i cannot get it work...and i feel really stupid!

I istalled FV v5 and i'm using it in a MVC 3 project.

I used :

RuleFor(b => b.cName).NotEmpty().WithLocalizedMessage(() => ViewRes.FormLabels.Required, ViewRes.FormLabels.Name);

where ViewRes.FormLabels.Required = "The {0} field is required"

and ViewRes.FormLabels.Name = "Name"

When I click on submit button the client side validation returns:

"The true field is required"

I then checked the data-val-required value in the input field and is equal to "The {0} field is required"
so i can realize that the argument I passed in the WithLocalizedMessage is never replaced...why??

I hope you could really help me in this
thanks
Fulvio

Created Unassigned: New feature request : Track current failures in validation context [7164]

$
0
0
Currently, while executing validation rules, one can not check if any previous failure has happened. My suggestion is extend the validation context to have all current failures. And add the validation context as an additional parameter to the "when" method.

This way, user can use something like

```
RuleFor(t => t.Name).NotEmpty();
RuleFor(t => t.Email).NotEmpty().Email();
RuleFor(t => t.Email).Must( e => check exists in the system ).When( ( m, ctx ) => ctx.HasFailure( m => m.Email) == false ) && ctx.HasFailure(m => m.Name) == false ) )
```

Currently I could find only one way to do this:

use private props in the class

```
private bool nameInvalid = false
private bool emailInvalid = false

RuleFor(t => t.Name).NotEmpty().OnAnyFailure(t => nameInvalid = true);
RuleFor(t => t.Email).NotEmpty().Email().OnAnyFailure(t => emailInvalid = true);
RuleFor(t => t.Email).Must( e => check email exists in the database ).When( m => !nameInvalid && !emailInvalid )
```

But this depends on private properties so when using composition with reusable validators, a validator instance can not access state of another validator instance.


New Comment on "Documentation"

$
0
0
I believe there misconceptions in the framework. First, do not think that the Framework should be responsible for setting up the error messages, it is a work of the interface. Often it is necessary to use business methods for validation and I found no easy mechanism for this using fluent validation.

New Post: My opnion

$
0
0
I believe there misconceptions in the framework. First, do not think that the Framework should be responsible for setting up the error messages, it is a work of the interface. Often it is necessary to use business methods for validation and I found no easy mechanism for this using fluent validation.
Viewing all 1917 articles
Browse latest View live