How to change JSON data format to Snake Case in ASP.NET Core Web API

The standard way to display data in ASP.NET Web API is Camel Case. But sometimes tasks arise when you need to change the data format to something else. For example, on the frontend, you might have a SPA that works with data in the snake case format. In this article, I'll show you how to change the serialization format in ASP.NET Core Web API.





Camel case vs Snake case
Camel case vs Snake case

This article provides code examples that you will need to transfer to your project. At the end of the post there is a link to the Github repository, where I have already configured the application to serialize in a snake case. All code samples and the project in the repository are written in ASP.NET Core .net5 version.





Changing the serialization format of server requests and responses

All we need to do to change serialization is set the Naming Policy in the application settings. The standard policy is Camel Case. Installing a policy on a Snake Case is a simple task.





First, let's add utilitarian methods for transforming strings to the snake case:





using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Utils.Helpers;

namespace YourNamespace
{
    public static class JsonSerializationExtensions
    {
        private static readonly SnakeCaseNamingStrategy _snakeCaseNamingStrategy
            = new SnakeCaseNamingStrategy();

        private static readonly JsonSerializerSettings _snakeCaseSettings = new JsonSerializerSettings
        {
            ContractResolver = new DefaultContractResolver
            {
                NamingStrategy = _snakeCaseNamingStrategy
            }
        };

        public static string ToSnakeCase(this T instance)
        {
            if (instance == null)
              {
                   throw new ArgumentNullException(paramName: nameof(instance));
               }

            return JsonConvert.SerializeObject(instance, _snakeCaseSettings);
        }

        public static string ToSnakeCase(this string @string)
        {
            if (@string == null)
              {
                   throw new ArgumentNullException(paramName: nameof(@string));
               }

            return _snakeCaseNamingStrategy.GetPropertyName(@string, false);
        }
    }
}

      
      



: , - . SnakeCaseNamingStrategy



  . Naming Policy: 





using System.Text.Json;
using Utils.Serialization;

namespace YourNamespace
{
    public class SnakeCaseNamingPolicy : JsonNamingPolicy
    {
        public override string ConvertName(string name) => name.ToSnakeCase();
    }
}

      
      



- ToSnakeCase()



. SnakeCaseNamingPolicy



  Startup.cs



 ConfigureServices



:





public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    // ...
    services
        .AddMvc()
        .AddJsonOptions(x =>
        {
            x.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy();
        });
    // ...
  }
}

      
      



, Web API, .AddMvc()



.AddControllers()



, . Web API MVC.





JSON Snake Case:





Snake Case data
Snake Case

, , …





Format for issuing validation errors so far in Camel Case
Camel Case

- , . , Camel Case, . , FirstName LastName Pascal Case, Snake Case. , .





, " " ASP . , :





using System;
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Mvc;

namespace YourNamespace
{
    public class ValidationProblemDetails : ProblemDetails
    {
        // 400 status ccode is usually used for input validation errors
        public const int ValidationStatusCode = (int)HttpStatusCode.BadRequest;

        public ValidationProblemDetails(ICollection validationErrors)
        {
            ValidationErrors = validationErrors;
            Status = ValidationStatusCode;
            Title = "Request Validation Error";
        }

        public ICollection ValidationErrors { get; }

        public string RequestId => Guid.NewGuid().ToString();
    }
}

      
      



, JSON. ProblemDetails



  Microsoft.AspNetCore.Mvc



. RequestId UI .





InvalidModelStateResponseFactory



:





using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Utils.Serialization;

namespace YourNamespace
{
    public class ValidationProblemDetailsResult : IActionResult
    {
        public async Task ExecuteResultAsync(ActionContext context)
        {
            var modelStateEntries = context.ModelState
                .Where(e => e.Value.Errors.Count > 0)
                .ToArray();

            var errors = new List();

            if (modelStateEntries.Any())
            {
                foreach (var (key, value) in modelStateEntries)
                {
                    errors.AddRange(value.Errors
                        .Select(modelStateError => new ValidationError(
                            name: key.ToSnakeCase(),
                            description: modelStateError.ErrorMessage)));
                }
            }

            await new JsonErrorResponse(
                context: context.HttpContext,
                error: new ValidationProblemDetails(errors),
                statusCode: ValidationProblemDetails.ValidationStatusCode).WriteAsync();
        }
    }
}

      
      



Startup.cs



:





public class Startup
{
   // ...
  public void ConfigureServices(IServiceCollection services)
  {
    // ...
    services
        .Configure(x =>
        {
            x.InvalidModelStateResponseFactory = ctx => new ValidationProblemDetailsResult();
        });
    // ...
  }
}

      
      



Snake Case :





Snake Case error structure
Snake Case

After all the changes, our application now not only sends and receives JSON data in the Snake Case format, but also shows validation errors in the form in which we need. Here you can open the Github repository from the link where there is an example of a configured application. Through the steps described, you can apply not only Snake Case, but also any other data serialization format that you like.








All Articles