I have a SQL Tables containing definition of dynamic grids (I'm using AGGrid library for Angular). Example:
TB_AGGrid_Definitions
ID | GridKey |
---|---|
1 | TestGrid |
TB_AGGrid_Columns
ID | GridId | Field |
---|---|---|
1 | 1 | FirstColumn |
2 | 1 | SecondColumn |
I'm using ASP.NET Core with EF Core for creating backend webapi service for my Angular Web application. I have a controller which can retrieve grid information.
Example JSON
{
"grid":{
"id":1,
"gridKey":"TestGrid",
"columns":[
{
"id":1,
"gridId":1,
"field":"FirstColumn"
},
{
"id":2,
"gridId":1,
"field":"SecondColumn"
}
]
}
}
I just would like to transform the value of Field
property in camelCase
using the same alghoritm of JsonSerializer.
I need to do this for binding properly the objects and the grid column definition which is case-sensitive.
If I send to AGGrid FirstColumn
as a field, it won't work with an object that has property named firstColumn
(which will be default behavior after default serialization).
I have fields like:
"IDTabella" --\> "idTabella"
"IDDTUltimoCommission" --\> "idDtUltimoCommission"
"NDGCliente" --\> "ndgCliente"
Automatic serialization works perfectly, but I can't replicate the same result with my own function.
Expected JSON
{
"grid":{
"id":1,
"gridKey":"TestGrid",
"columns":[
{
"id":1,
"gridId":1,
"field":"firstColumn"
},
{
"id":2,
"gridId":1,
"field":"secondColumn"
}
]
}
}
As you specifically asked for the camelCasing
-algorithm that the JsonSerializer
uses in .NET. Here is the implementation of that taken from the official open source repository for the .NET runtime on Github (See Github - dotnet/runtime).
Implementation on current
main
branch with the last commit having the hash3138a80
which is already after .NET 8 was released.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Text.Json
{
internal sealed class JsonCamelCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
if (string.IsNullOrEmpty(name) || !char.IsUpper(name[0]))
{
return name;
}
#if NETCOREAPP
return string.Create(name.Length, name, (chars, name) =>
{
name.CopyTo(chars);
FixCasing(chars);
});
#else
char[] chars = name.ToCharArray();
FixCasing(chars);
return new string(chars);
#endif
}
private static void FixCasing(Span<char> chars)
{
for (int i = 0; i < chars.Length; i++)
{
if (i == 1 && !char.IsUpper(chars[i]))
{
break;
}
bool hasNext = (i + 1 < chars.Length);
// Stop when next char is already lowercase.
if (i > 0 && hasNext && !char.IsUpper(chars[i + 1]))
{
// If the next char is a space, lowercase current char before exiting.
if (chars[i + 1] == ' ')
{
chars[i] = char.ToLowerInvariant(chars[i]);
}
break;
}
chars[i] = char.ToLowerInvariant(chars[i]);
}
}
}
}
As one would imagine it's quite well implemented with performance in mind i. e. avoiding heap allocations mainly by using Span<T>
where necessary and usage of some methods you would typically only use when you really care about performance (like string.Create()
here).