skip to Main Content

I am trying to build a JsonElement (or similar) using a camelCase convention from a PascalCase string using System.Text.Json. Is there a way to enforce that behavior?

var jsonString = "{"Property1":"s", "PropertyCamel":{"PropertyNested":"g"}, "PPP":[{"NestedList":"1"}]}";
var deserialized = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(jsonString,
    new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = true
    });
var serialized = System.Text.Json.JsonSerializer.Serialize(
    deserialized,
    new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = true
    });
// deserialized outputs property names in PascalCase

I have also tried deserializing -> serializing -> deserializing but without success.

Is there a way of doing so?

2

Answers


  1. Referring to this answer, using Newtonsoft.Json

    using Newtonsoft.Json;
    using Newtonsoft.Json.Serialization;
    using System.Dynamic;
        
    var jsonString = "{"Property1":"s", "PropertyCamel":{"PropertyNested":"g"}, "PPP":[{"NestedList":"1"}]}";
                    // won't work if I used json
                    // var json = JsonConvert.DeserializeObject(jsonString);
                    var interimObject = JsonConvert.DeserializeObject<ExpandoObject>(jsonString);
                    var jsonSerializerSettings = new JsonSerializerSettings
                    {
                        ContractResolver = new CamelCasePropertyNamesContractResolver()
                    };
                    var myJsonOutput = JsonConvert.SerializeObject(interimObject, jsonSerializerSettings);
    

    enter image description here

    Login or Signup to reply.
  2. There is no way to load or deserialize a JsonDocument or JsonElement and convert it to camelCase during the loading process. JsonDocument and JsonElement are just read-only, structured views of the utf-8 JSON byte sequence from which they were loaded and as such there’s no way to transform the view during (or after) the parsing process. For confirmation, JsonDocument, JsonElement and Utf8JsonReader are all sealed and JsonElement has no publicly accessible constructor so there simply isn’t an extension point to inject custom transformation of property names.

    As an alternative, you could camel-case the property names during re-serialization by creating the following custom JsonConverter<JsonElement>:

    public class JsonElementConverter : JsonConverter<JsonElement>
    {
        public override void Write(Utf8JsonWriter writer, JsonElement value, JsonSerializerOptions options)
        {
            switch (value.ValueKind)
            {
                case JsonValueKind.Object:
                    var policy = options.PropertyNamingPolicy;
                    writer.WriteStartObject();
                    foreach (var pair in value.EnumerateObject())
                    {
                        writer.WritePropertyName(policy?.ConvertName(pair.Name) ?? pair.Name);
                        Write(writer, pair.Value, options);
                    }
                    writer.WriteEndObject();
                    break;
                case JsonValueKind.Array:
                    writer.WriteStartArray();
                    foreach (var item in value.EnumerateArray())
                        Write(writer, item, options);
                    writer.WriteEndArray();
                    break;
                default:
                    value.WriteTo(writer);
                    break;
            }
        }
        
        public override JsonElement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            using var doc = JsonDocument.ParseValue(ref reader);
            return doc.RootElement.Clone();
        }
    }
    

    And then re-serializing your JsonDocument.RootElement using JsonSerializer like so:

    using var doc = JsonDocument.Parse(jsonString);
    
    JsonNamingPolicy policy = JsonNamingPolicy.CamelCase;
    var options = new JsonSerializerOptions
    {
        Converters = { new JsonElementConverter() },
        PropertyNamingPolicy = policy,
        WriteIndented = true // Or false, if you prefer
    };
    
    var serialized = JsonSerializer.Serialize(doc.RootElement, options);
    

    Notes:

    • Be sure to serialize the JsonDocument.RootElement rather than the JsonDocument. If you serialize the document directly the converter is never invoked.

    • In .NET 6 it should be possible to transform the property names during deserialization/loading using a custom converter by deserializing to the new JsonNode DOM, whose elements can be constructed and modified directly by applications code.

    • As an alternative, if you don’t require use of JsonElement, you could consider deserializing to an ExpandoObject or similar and remapping the properties during deserialization by extending ObjectAsPrimitiveConverter from this answer to C# – Deserializing nested json to nested Dictionary<string, object> to do the necessary name transformation.

    Demo fiddle here.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search