How to enable escaped JSON string parsing in asp.net core?

35 Views Asked by At

When I send a request to the endpoint with an escaped JSON string it throws an exception "JSON value could not be converted to Test.TestClass . Path: $ | LineNumber: 0 | BytePositionInLine: 90.\r\n"". How can I enable escaped JSON string parsing in ASP.NET 5? I am using System.Text.Json (v 6.0.1). Tried updating to (v8) but no luck. Also tried using AddNewtonsoftJson() but still got the same result.

Creating a custom JSON converter works but need a solution which applies globally.

The curl for my request with the escaped JSON string.

curl --location 'https://localhost:8080/api/testEndpoint' \
--header 'charset: utf-8' \
--header 'Content-Type: application/json' \
--data '"{\"testId\":0,\"created\":\"2024-03-09T14:17:19.9837955Z\"}"'

The model class

public class TestClass 
{
  public int TestId {get;set;}
  public DateTime Created {get;set;}
}
1

There are 1 best solutions below

0
Lakshin Karunaratne On BEST ANSWER

The issue was the client was double serializing the the request JSON. Thanks @Panagiotis Kanavos for pointing out.

However, until the client side issue is resolved I created a custom JSON converter to temporarily handle the issue. And posting it since it could be useful to anyone else for a different purpose.

In the below code just implement a blank interface 'IJSONStringDto' to the endpoint dtos and the converter will handle the normal JSON parsing and double serialized JSON parsing.

    public class JSONStringConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        if (typeof(IJSONStringDto).IsAssignableFrom(typeToConvert))
        {
            return true;
        }

        return false;
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        JsonConverter converter = (JsonConverter)Activator.CreateInstance(
           typeof(JSONStringObjectConverter<>).MakeGenericType(
               new Type[] { typeToConvert }),
           BindingFlags.Instance | BindingFlags.Public,
           binder: null,
           args: new object[] { options },
           culture: null);

        return converter;
    }

    private class JSONStringObjectConverter<TJSONStringType> : JsonConverter<TJSONStringType> where TJSONStringType: IJSONStringDto
    {
        public JSONStringObjectConverter(JsonSerializerOptions options)
        {

        }

        public override TJSONStringType? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                return JsonSerializer.Deserialize<TJSONStringType>(reader.GetString());
            }

            using (var jsonDoc = JsonDocument.ParseValue(ref reader))
            {
                return JsonSerializer.Deserialize<TJSONStringType>(jsonDoc.RootElement.GetRawText());
            }
        }

        public override void Write(Utf8JsonWriter writer, TJSONStringType value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    }
}

Then register the converter

.AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new JSONStringConverterFactory());
    
});