Home > Back-end >  Enum fluent validation to accept only string
Enum fluent validation to accept only string

Time:04-08

Below is my Enum

public enum IdentifierType
{
    Customer = 1,
    Manager = 2,
    Director = 3
}

Using fluent validation in .Net core, is it possible to do validation where passing 1/"1" or 2/"2" or 3/"3" in the request should return validation error?

Passing "Customer" or "Manager" etc should work fine.

I know in C# enum type is 'int' but any thoughts if this is doable in first place?

Setup in startup.cs: Validator is registered before my converter.

services.AddControllers()
        .AddFluentValidation(configuration =>
        {
          configuration.RegisterValidatorsFromAssemblyContaining<Startup>();
        })
          .ConfigureApiBehaviorOptions(opt => { opt.SuppressModelStateInvalidFilter = true; })
          .AddJsonOptions(serializerOption =>
          {
            serializerOption.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
            serializerOption.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
            serializerOption.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
          });

Attached behaviour of API using postman

enter image description here enter image description here

CodePudding user response:

The MVC framework has to convert JSON to a class for FluentValidation to work.

However, you can configure MVC to validate it first.

To allow the built-in JSON serialiser in any ASP.NET MVC Core app to allow strings to be converted into an enum, you need to add the JsonStringEnumConverter converter in your app startup. This converter also has a parameter you can set to false to disallow integer values. For example:

services
    .AddMvc()
    .AddJsonOptions(opts =>
    {
        opts.JsonSerializerOptions.Converters.Add(
            new JsonStringEnumConverter(allowIntegerValues: false));
    })

Since it seems that '' won't prevent an int being passed in as a string, you can write your own converter. For example, something like this would work:

public class IdentifierTypeConverter : JsonConverter<IdentifierType>{
    public override IdentifierType Read(ref Utf8JsonReader reader, 
        Type typeToConvert, JsonSerializerOptions options)
    {
        var value = reader.GetString();
        
        if(value == null)
        {
            throw new Exception("No null values thanks!");  
        }
        
        if(int.TryParse(value, out var _))
        {
            throw new Exception("No numbers thanks!");
        }
        
        return (IdentifierType)Enum.Parse(typeof(IdentifierType), value);
    }

    public override void Write(Utf8JsonWriter writer, IdentifierType value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

CodePudding user response:

AFAIK there is no direct solution in fluent validations to solve your problem. However, I would handle this scenario something as stated below:

In the below code, I have created two properties - The IdentifierType field is public and it will accept a string value from your client. The other field is an enum and it can be used internally inside your project.

public class YourRequestModel
{
   internal IdentifierType IdType
   {
     get
     {
        return Enum.Parse<IdentifierType>(IdentifierType);
     }
    }
   public string IdentifierType { get; }
}

While doing fluent validation, validate the input only against the string value.

public class YourRequestModelValidator: AbstractValidator<YourRequestModel> 
{
  RuleFor(x => x.IdentifierType)
            .IsEnumName(typeof(IdentifierType), caseSensitive: false);
}
  • Related