Aleksej_Shherbak
Aleksej_Shherbak

Reputation: 3078

How I can set JSON serialization rules for validation messages?

I have the following configuration of JSON policy in my Startup.cs:

services.AddControllers().ConfigureApiBehaviorOptions(options =>
    {
        options.SuppressInferBindingSourcesForParameters = true;
        options.SuppressModelStateInvalidFilter = true;
        // options.SuppressMapClientErrors = true;
    }) 
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy =
            SnakeCaseNamingPolicy.Instance;
    });

And policy:

public class SnakeCaseNamingPolicy : JsonNamingPolicy
{
    public static SnakeCaseNamingPolicy Instance { get; } = new SnakeCaseNamingPolicy();

    public override string ConvertName(string name)
    {
        // Conversion to other naming conventaion goes here. Like SnakeCase, KebabCase etc.
        return name.ToSnakeCase();
    }
}

And ToSnakeCase:

public static class StringUtils
{
    public static string ToSnakeCase(this string str)
    {
        return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() 
            : x.ToString())).ToLower();
    }
}

I use it to have ability of getting JSON in snake_case.

Here is my model:

public class CategoryViewModelCreate
{
    [Required(ErrorMessage = "Inner id is required")]
    [JsonPropertyName("inner_id")]
    public int? InnerId { get; set; }

    [Required(ErrorMessage = "Name is required")]
    [JsonPropertyName("name")]
    public string Name { get; set; }
}

My controller is:

public async Task<IActionResult> Create([FromBody] CategoryViewModelCreate viewModel)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

And now it works fine if I have the following JSON:

{
    "name": "testing",
    "inner_id": 123
}

But if my JSON is (without name):

{
    "inner_id": 123
}

I have the following validation message:

{
  "Name": [
    "Name is required"
  ]
}

But it's wrong. I would like to have (name instead of Name and snake_case for the other keys):

{
  "name": [
    "Name is required"
  ]
}

How to set up it? Where? As you can see I'm trying to use [JsonPropertyName("name")], but without any success(

I appreciate any help.

Upvotes: 0

Views: 381

Answers (1)

Dmitry
Dmitry

Reputation: 322

You can create your base inherited controller and ovveride BadRequest(ModelStateDictionary m) method

BadRequest(ModelStateDictionary model)
{
    var newModel = model.ToDictionary(
            x => x.Key.ToCamelCase(),  
            x => kvp.Value
        );
    base.BadRequest(newModel);
}

Something like this

Upvotes: 1

Related Questions