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

New Post: Data Annotations + Fluent (How to Ignore Attributes).

$
0
0
Hi,

I have fluent validation configured like this.
FluentValidationModelValidatorProvider.Configure(
    _ =>
        {
            // This does not seem to work, or i am misunderstanding it?
            _.AddImplicitRequiredValidator = false;
        });
I have a model that contains two objects Person and Organisation.
I am trying to use validation selectively with this.
public class PartyModelValidator : AbstractValidator<PartyModel>
{
    /// <summary>
    /// Initialises a new instance of the <see cref="PartyModelValidator"/> class.
    /// </summary>
    public PartyModelValidator()
    {
        this.RuleFor(_ => _.Client)
            .SetValidator(new ClientValidator())
            .When(_ => _.SelectedPartyTab == PartyType.Person);
        this.RuleFor(_ => _.Organisation)
            .SetValidator(new OrganisationValidator())
            .When(_ => _.SelectedPartyTab == PartyType.Organisation);
When the organisation is null, the required data annotation attributes result in validation errors. When the person is null, the required data annotation attributes result in validation errors.

How do I stop the data annotation errors. I am confident that fluent validation is being called, because the custom messages show up. They are there in addition to the required field attributes being validated. Is there a way of clearing all the data annotation errors before fluent supplies it's own errors. That way I can use one or the other, and not both together.

Removing the attributes is a problem for me. They are generated, and are there for a reason.
I know this is a bit of a hybrid solution. The data annotations work just fine for the simple case, and I am happy for them to be there, just not when I have built a specific fluent validator.

I am using MVC4 and the latest (nuget) release of everything.

Thanks.

New Post: Validators using Interface as Entity

$
0
0
I'm not able to reproduce this. The following code works as expected:
public class TypeProduitValidator : AbstractValidator<ITypeProduit> {
    public TypeProduitValidator() {
        RuleFor(typeProduit => typeProduit.Code).NotNull().NotEmpty();
        RuleFor(typeProduit => typeProduit.Designation).NotNull().NotEmpty();
    }
}

public interface ITypeProduit
{
    string Code { get; set; }
    string Designation { get; set; }
}

public class TypeProduit : ITypeProduit {
    public string Code { get; set; }
    public string Designation { get; set; }
}

[TestFixture]
public class Tests
{
    [Test]
    public void Sample()
    {
        var typeProduitValidator = new TypeProduitValidator();
        var typeProduitInstance = new TypeProduit(); 
        typeProduitValidator.ShouldHaveValidationErrorFor(typeProduit => typeProduit.Code ,typeProduitInstance );
    }
}
Check your stack trace to see where the error is coming from.

Jeremy

New Post: Validators using Interface as Entity

$
0
0
This case works at my side as well. But what i want is to test the validator for null values which not work at my side.

Can you please make the same test for null value??

New Post: Validators using Interface as Entity

$
0
0
The code I posted is for a null value of the Code property. As you can see, I left the Code property blank for the TypeProduit instance, but the TypeProduit instance itself can't be null - you must supply a non-null instance to the Validate method.

New Post: Validators using Interface as Entity

$
0
0
Ok, I used your approach and work. I think, I have to continue handling this kind of case like that. Thanks a lot Jeremy.

New Post: MVC Editor Template Client Side Validation

$
0
0
Your suggestion worked. Thanks for your help, Jeremy!

New Post: CustomizeValidatorAttribute for Web Api?

$
0
0
Any thoughts on how to implement FluentValidation for MVC's 'CustomizeValidatorAttribute' in FluentValidation for Web Api? Specifically I'd like to be able to customize the 'IValidatorSelector' used so that I can specify RuleSets on the parameter level:
public void Post([FromBody, CustomizeValidator(RuleSet="Create")]EventDto @event)
{
        //perform an insert
}

public void Put(int id, [FromBody, CustomizeValidator(RuleSet="Update")]EventDto value)
{
        //perform an update
}
I played around with a custom attribute that I pulled out in the 'FluentValidationBodyModelValidator' but it seems really sloppy (and is even more sloppy when constructing and passing around the 'IValidatorSelector') and potentially expensive given all the reflection happening.

So, something like this in FluentValidationBodyModelValidator's Validate method:
            string actionName = actionContext.ActionDescriptor.ActionName;

            var attribute = (CustomizeValidatorWebApiAttribute) actionContext.ControllerContext.Controller.GetType().GetMethods()
                                         .Where(x => x.Name == actionName)
                                         .First()
                                         .GetParameters()
                                         .Where(x => x.Name == keyPrefix)
                                         .First()
                                         .GetCustomAttributes(typeof(CustomizeValidatorWebApiAttribute), false)
                                         .FirstOrDefault();
            if (attribute != null)
            {
                RuleSet = !string.IsNullOrEmpty(attribute.RuleSet) ? attribute.RuleSet.Split(',', ';') : new string[] { };
            }
Any ideas?

New Post: set validation message after rule has run

$
0
0
Hello Jeremy.

I have this complex case when I need to validate a property against a set of rules. These rules are in the form of JavaScript that can be run on the server, but that is not really important I guess.
The rule looks approximately like this:
string errorMessage = "Something generic";
RuleFor(x => x.SomeProperty)
    .Must((z, c) => ValidateCustomValidator(z.CustomValidationRuleSet, c, out errorMessage))
    .WithMessage(errorMessage)
    .When(x => x.CustomValidationRuleSet != null);
The ValidateCustomValidator method looks approximately like this:
private bool ValidateCustomValidator(CustomValidationRuleSet ruleSet, string valueToValidate, out errorMessage) {
    foreach (var rule in ruleSet.Rules)
    {
         bool isValid = EvaluateJsRuleOnServer(rule, valueToValidate);
         if(!isValid)
         {
             errorMessage = rule.ErrorMessage;
             return false;
         }
    }
    errorMessage = "";
    return true;
}
As you can see, I'm attempting to run validation rules and if one of them fails, get the error message from that rule object, pass it back with the out parameter and use it in the .WithMessage method. This does not work because I think .WithMessage method runs before the actual validation.

Would you have a suggestion how this could be worked around?

New Post: set validation message after rule has run

New Post: SetValidator() and client side validation in MVC

$
0
0
I have some models that contain complex data types. As a simple example:
    public class ApplicationInformationModel
    {
        public Person ContactName{ get; set; }
        public Address MailingAddress { get; set; }
    }


    public class Address
    {
        public string Street1{ get; set; }
        public string Street2 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Zip { get; set; }
    }

    public class Person
    {
        public string Prefix { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Suffix { get; set; }
    }
I created a validator for Person and Address, and I used the FluentValidation.Attributes.Validator() annotation at the top of these classes to have the rules applied automatically to the instances of Person and Address in ApplicationInformationModel.

Then, I ran into a situation where another parent model used instances of Person and Address:
    public class AdditionalPayee
    {
        public bool HasAdditionalPayee {get; set; }
        public Address Address { get; set; }
        public Person Contact { get; set; }
        public string Phone { get; set; }
    }
For the AdditionalPayee class, I only want to validate Person and Address if HasAdditionalPayee is true. The "validator" attribute described above causes any instances of Address and Person to get validated all the time, and I don't want that here unless HasAdditionalPayee is true. So, I removed the attribute and I re-wrote the rules in the ApplicationInformationModelValidator class to be:
            RuleFor(x => x.MailingAddress).SetValidator(new AddressValidator());
            RuleFor(x => x.ContactName).SetValidator(new PersonValidator());
and in the AdditionalPayeeValidator class to be conditional:
            RuleFor(x => x.Contact).SetValidator(new PersonValidator()).When(x => x.HasAdditionalPayee);
            RuleFor(x => x.Address).SetValidator(new AddressValidator()).When(x => x.HasAdditionalPayee);
This works, but only on the server-side. None of the validations fire on the client-side. Is that just the way it is?

New Post: Validating single rule if the first rule fails.

$
0
0
I have looked at the CascadeMode.StopOnFirstFailure and the documentation listed above, but I think I am just doing something wrong because it just continues and eventually throws an exceptoin... {"Object reference not set to an instance of an object."}
So I am sure this is just crazy simple, but I am not seeing it... :(
 class Program
    { /// <summary>
        /// Entry point into console application.
        /// </summary>
        static void Main(string[] args)
        {

            List<string> requiredFields = new List<string>() { "Room", "Tag", "Serial", "Status" };
            List<string> selectedFields = new List<string>() { "Room", "Tag", "Serial", "Department", "SiteUID" };

            ReceiveByTagImport import = new ReceiveByTagImport();
            ImportByTagValidator validator = new ImportByTagValidator();
            validator.CascadeMode = CascadeMode.StopOnFirstFailure;

            //Not sure about this statement...
            ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;



            var results = validator.Validate(import);
            foreach (var result in results.Errors)
            {
                Console.WriteLine("Property name: " + result.PropertyName);
                Console.WriteLine("Error: " + result.ErrorMessage);
                Console.WriteLine("");
            }

            // Wait for user
            Console.ReadKey();

        }
    }

    public class ImportByTagValidator : AbstractValidator<ReceiveByTagImport>
    {
        public ImportByTagValidator()
        {
 // First set the cascade mode
            CascadeMode = CascadeMode.StopOnFirstFailure;

            RuleFor(r => r.RequiredFields).NotNull();
           //  THIS CODE KICKS OUT AN EXCEPTION... BUT SHOULD NOT GET EXECUTED...
            RuleFor(r => r.RequiredFields.Count).GreaterThan(0);

        }
    }


    public class ReceiveByTagImport
    {
        public int ExpectedQuantity { get; set; }
        public List<string> RequiredFields { get; set; }

    }

New Post: Validating single rule if the first rule fails.

$
0
0
I updated the ImportByTagValidator Class using WHEN and that seems to have fixed my issue...
Is this the correct approach?
 public class ImportByTagValidator : AbstractValidator<ReceiveByTagImport>
    {
        public ImportByTagValidator()
        {
            // First set the cascade mode
            CascadeMode = CascadeMode.StopOnFirstFailure;

            RuleFor(r => r.RequiredFields).NotNull();

            RuleFor(r => r.RequiredFields.Count).GreaterThan(0).When(x => x.RequiredFields != null);

        }
    }

New Post: Validate Two List and return missing elements..

$
0
0
Playing around trying to use the validator to compare two list and return what is missing if they are not a match..
  List<string> requiredFields = new List<string>() { "Room", "Tag", "Serial", "Status" };
            List<string> selectedFields = new List<string>() { "Room", "Tag", "Serial", "Department", "SiteUID" };

...
// This code will return a list of the differences...
 return import.RequiredFields.Except(selectedFields);
So what I am trying to figure out is how to do this with the validator... Any suggestions?

New Post: SetValidator() and client side validation in MVC

$
0
0
Hi,

Yes, I'm afraid that if you want to use client-side validation then each class needs to have the attribute applied separately - using SetValidator will only run on the server.

Jeremy

New Post: Validate Two List and return missing elements..


New Post: Validating single rule if the first rule fails.

$
0
0
Hi

CascadeMode applies to rules in the same chain. That is, if you have two rules against the same property:
RuleFor(x => x.SomeProperty).NotNull().GreaterThan(5);
If CascadeMode is set to StopOnFirstFailure, then the GreaterThan rule wouldn't be executed if the NotNull fails. If you have separate RuleFor definitions, then CascadeMode does not apply.

Your approach of using a When clause is correct.

Jeremy

New Post: Validate Two List and return missing elements..

$
0
0
I have done what Jeremy suggests a number of times and it works nicely. There are two approaches that you could take. Perform the check within the validator against two collections passed in as properties of the class under test as Jeremy suggested.

The other approach is if you know what the required fields are outside of the context of the class under test. For example, they might be in a database or config.

In that case, you should inject a service into your validator. This service knows what the required values are and you pass the test values to it: FindMismatches(x)
    public class ItemWithAStringCollection
    {
        public List<string> StringCollection { get; set; }
    }

    public class SomeValidator : AbstractValidator<ItemWithAStringCollection>
    {
        private Dictionary<string, List<string>> _mismatches;
        private readonly IStringCollectionCheckingService _stringCollectionCheckingService;
        public SomeValidator(IStringCollectionCheckingService stringCollectionCheckingService)
        {
            _stringCollectionCheckingService = stringCollectionCheckingService;
            RuleFor(x => x.StringCollection)
                .Must(x =>
                {
                    //Save to instance field for use in WithMessage(...) (Jeremy - is there a better way to do this?)
                    _mismatches = _stringCollectionCheckingService.FindMismatches(x);
                    //Return result to trigger failure/pass
                    return _mismatches.Count == 0; 
                })
                .WithMessage("The following mismatches occurred: {0}", x =>
                {
                    var sb = new StringBuilder();
                    foreach (var mismatch in _mismatches)
                    {
                        sb.AppendLine("Mismatches of type: " + mismatch.Key);
                        foreach (var value in mismatch.Value )
                        {
                            sb.AppendLine(value);
                        }
                    }
                    return sb.ToString();
                });
        }
    }

    //Implement this internally using List<string> Except or whatever you like to determine the mismatches. 
    //I used a Dictionary<string, List<string>> keyed on the type of mismatch, depending on whether the string was missing in one or the other collection.
    //But you might just like to return a List<string> for use in the ErrorMessage.
    public interface IStringCollectionCheckingService
    {
        Dictionary<string, List<string>> FindMismatches(IEnumerable<string> input);
    }

New Post: Validate Two List and return missing elements..

$
0
0
I have tried two approaches on this...
            RuleFor(r => itemWithAStringCollection)
                .Must(r => !r.RequiredList.Except(r.SelectedList).Any() ).WithMessage("Missing Required {0}",string.Join(",",itemWithAStringCollection.RequiredList.Except(itemWithAStringCollection.SelectedList)));
The other
RuleFor(r => itemWithAStringCollection)
                .Must(RequiredFieldsCheck)
                .WithMessage("My Message:{0}", r => r.MissMatch);
While this code is not polished I have included both methods. I used this code to see if Fluent Validation could solve my problems.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentValidation;
using FluentValidation.Results;
using FluentValidation.Validators;


namespace ValidationTest
{
    internal class Program
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>
        private static void Main(string[] args)
        {

            List<string> requiredFields = new List<string>() { "Room", "Tag", "Serial", "Status" };
            List<string> selectedFields = new List<string>() { "Room", "Tag", "Serial", "Department", "SiteUID" };
            ItemWithAStringCollection itemWithAStringCollection = new ItemWithAStringCollection()
                {
                    RequiredList = requiredFields,
                    SelectedList = selectedFields
                };


            ImportByTagValidator validator = new ImportByTagValidator(itemWithAStringCollection);

            validator.CascadeMode = CascadeMode.StopOnFirstFailure;

            //Not sure about this statement...
            ValidatorOptions.CascadeMode = CascadeMode.StopOnFirstFailure;

            var results = validator.Validate(itemWithAStringCollection);
            foreach (var result in results.Errors)
            {
                Console.WriteLine("Property name: " + result.PropertyName);
                Console.WriteLine("Error: " + result.ErrorMessage);
                Console.WriteLine("");
            }

            // Wait for user
            Console.ReadKey();

        }


        public class ImportByTagValidator : AbstractValidator<ItemWithAStringCollection>
        {


            public ImportByTagValidator(ItemWithAStringCollection itemWithAStringCollection)
            {
                // First set the cascade mode
                CascadeMode = CascadeMode.StopOnFirstFailure;

                RuleFor(r => r.RequiredList).NotNull();
                RuleFor(r => r.SelectedList.Count).GreaterThan(0).When(x => x.RequiredList != null);
                RuleFor(r => itemWithAStringCollection)
                    .Must(RequiredFieldsCheck)
                    .WithMessage("Missing Required Field(s):{0}", r => r.MissMatch);


                RuleFor(r => itemWithAStringCollection)
                    .Must(r => !r.RequiredList.Except(r.SelectedList).Any())
                    .WithMessage("Missing Required {0}",
                                 string.Join(",",
                                             itemWithAStringCollection.RequiredList.Except(
                                                 itemWithAStringCollection.SelectedList)));


            }

            public bool RequiredFieldsCheck(ItemWithAStringCollection itemWithAStringCollection)
            {

                itemWithAStringCollection.RequiredList.Sort();
                itemWithAStringCollection.SelectedList.Sort();
                var result = itemWithAStringCollection.RequiredList.Except(itemWithAStringCollection.SelectedList);
                itemWithAStringCollection.MissMatch = string.Join(",", result);
                if (itemWithAStringCollection.MissMatch.Length == 0)
                {
                    return true;
                }

                return false;
            }
        }


        public class ItemWithAStringCollection
        {
            public List<string> RequiredList { get; set; }
            public List<string> SelectedList { get; set; }
            private string _missMatch = String.Empty;

            public string MissMatch // Not used in one of the approaches...
            {
                get { return _missMatch; }
                set { _missMatch = value; }
            }
        }



    }
}

New Post: Pure inline validation without validation/DTO classes

$
0
0
Hi,

I like the structure of creating validation classes for my DTO classes. However, in certain places all I want to do is to validate some input parameters, without them being structured in any way. At the same time, this validation is one-time and I'd rather not create a validation class, an object DTO and so forth. Basically I'm looking for a syntax like this:
Guard.Check(myVariable)
    .NotNull()
    .GreaterThan(5)
    .WithMessage("Must be at least 5 characters")
    .Validate()
Or the Check() could be at the end and serve as the initiator of the validation, though the above is more readable in my opinion, and allows type inference early on.

Am I correct in concluding that this isn't possible using FluentValidation? Is this something you'd be interested in having? If so I'll work on a pull request. If not, totally OK, I'll brew something myself :)

Cheers,
Mark S. Rasmussen

New Post: Pure inline validation without validation/DTO classes

$
0
0
Hi Mark

No, I'm afraid this isn't something that FluentValidation supports. FluentValidation is designed for defining rules against properties on objects for viewmodels, so this would be out-of-scope for the project and isn't something I intend to add.

That being said, it'd probably be technically possible with a bit of work, so you could build on top of FluentValidation to add support for this in your own project, but isn't something that I'd want to merge into the core.

Jeremy
Viewing all 1917 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>