Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FluentValidation validate Enum value

I have the following model:

public class ViewDataItem
{
    public string viewName { get; set; }
    public UpdateIndicator updateIndicator { get; set; }
}

With the following enum:

public enum UpdateIndicator
{
    Original,
    Update,
    Delete
}

And the following Validator:

public class ViewValidator : AbstractValidator<ViewDataItem>
{
    public ViewValidator()
    {
        RuleFor(x => x.viewName).NotEmpty().WithMessage("View name must be specified");
        RuleFor(x => x.updateIndicator).SetValidator(new UpdateIndicatorEnumValidator<UpdateIndicator>());
    }
}

public class UpdateIndicatorEnumValidator<T> : PropertyValidator
{
    public UpdateIndicatorEnumValidator() : base("Invalid update indicator") {}

    protected override bool IsValid(PropertyValidatorContext context)
    {
        UpdateIndicator enumVal = (UpdateIndicator)Enum.Parse(typeof(UpdateIndicator), context.PropertyValue.ToString());

        if (!Enum.IsDefined(typeof(UpdateIndicator), enumVal))
          return false;

        return true;
    }
}

The code is in a WebAPI that receives data via JSON, deserialize it to an object and then validates, but for some reason I can send whatever I please in the updateIndicator, so long as I don't put in an integer value larger than the max index in the enum (i.e 1,2 or 3 works fine, but 7 will generate an error).

How can I get this to validate the input of the data I receive to see if that value is actually in the Enum?

like image 632
JaggenSWE Avatar asked Jul 10 '17 13:07

JaggenSWE


People also ask

How does fluent validation work?

Fluent validations use Fluent interface and lambda expressions to build validation rules. Fluent validation is a free-to-use . NET validation library that helps you make your validations clean and easy to both create and maintain. It even works on external models that you don't have access to, with ease.

Is fluent validation open source?

FluentValidation is an open source validation library for . NET. It supports a fluent API, and leverages lambda expressions to build validation rules.


2 Answers

Try the built-in IsInEnum()

RuleFor(x => x.updateIndicator).IsInEnum();

This checks if the provided enum value is within the range of your enum, if not, the validation will fail:

"'updateIndicator' has a range of values which does not include '7'."

like image 162
Stacked Avatar answered Oct 05 '22 12:10

Stacked


The problem arises from the fact that the API model builder will convert what is sent to an enum. If a value isn't found, it doesn't populate it, and the default value is used (as it would be with any other property data type that isn't populated).

In order to easily tell if the value sent is a valid enum value, you should make your property nullable. That way, if a value isn't able to be parsed, it will be set to null. If you want to ensure that the property is set, just have your validator not allow null values for it.

public class ViewDataItem
{
    public string viewName { get; set; }
    public UpdateIndicator? updateIndicator { get; set; }
}

public class ViewValidator : AbstractValidator<ViewDataItem>
{
    public ViewValidator()
    {
        RuleFor(x => x.viewName).NotEmpty().WithMessage("View name must be specified");
        RuleFor(x => x.updateIndicator).NotNull();
    }
}

Without setting the property to null, your model will always have a valid value when you have it. Alternatively, you could have the first value of your enum be a dummy value, but that would be a code smell. A null model property makes far more sense.

If you want to find out what the actual value that was sent to the API endpoint was, you'll need to look at creating an HTTP Handler, which is beyond the scope of this question.

like image 29
krillgar Avatar answered Oct 05 '22 11:10

krillgar