Home > database >  Move from Newtonsoft.Json to System.Text.Json and Guid problem
Move from Newtonsoft.Json to System.Text.Json and Guid problem

Time:05-19

I have a .NET 5 ASP REST service and I'm trying to remove Newtonsoft with System.Text.
Problem is that with Newtonsoft I was able to send GUID's without dashes and the model was bonded successfully, now I get nulls (with System.Text.Json)

I was able to isolate the problem using https://dotnetfiddle.net/ocayBp

using System;

public class Program
{
    public static void Main()
    {
        //this works
        var json = "{\"AuthorId\":\"6917d697-c1ab-4fb7-b297-8b2a23100bfc\",\"Title\":\"test title\"}";
        //this doesn't work
        //var json = "{\"AuthorId\":\"6917d697c1ab4fb7b2978b2a23100bfc\",\"Title\":\"test title\"}";
        var result1 = Newtonsoft.Json.JsonConvert.DeserializeObject<Post>(json);
        result1.Dump();
        var result2 = System.Text.Json.JsonSerializer.Deserialize<Post>(json);
        result2.Dump();
    }
}

public class Post
{
    public Guid AuthorId { get; set; }

    public string Title { get; set; }
}

Newtonsoft correctly deserialized string to GUID, with System.Text.Json approach I get this error:

Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to System.Guid. Path: $.AuthorId | LineNumber: 0 | BytePositionInLine: 46. ---> System.FormatException: The JSON value is not in a supported Guid format. at System.Text.Json.Utf8JsonReader.GetGuid() at System.Text.Json.Serialization.Converters.GuidConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) at System.Text.Json.Serialization.Metadata.JsonPropertyInfo1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value) at System.Text.Json.Serialization.JsonConverter1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value) at System.Text.Json.Serialization.JsonConverter1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) --- End of inner exception stack trace --- at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex) at System.Text.Json.Serialization.JsonConverter1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state) at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable1 actualByteCount) at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan1 json, JsonTypeInfo jsonTypeInfo) at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options) at Program.Main()

I'm setting up JSON in ConfigureServices:

services.AddControllers(
    options =>
    {
        options.ValueProviderFactories.Add(new ClaimValueProviderFactory());
    }).AddJsonOptions(options =>
{
    options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
    options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});

How can I get the same behavior with System.Text.Json as with Newtonsoft.Json.

I found an issue on GitHub(https://github.com/dotnet/runtime/issues/30692) but there is no TryGetGuid method where you can specify the format.

CodePudding user response:

We can try to write a customer JsonConverter for Guid by JsonConverter<T>

public class GuidJsonConverter: JsonConverter<Guid>
{
    public override Guid Read(
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options) =>
                Guid.Parse(reader.GetString()!);

    public override void Write(
            Utf8JsonWriter writer,
            Guid value,
            JsonSerializerOptions options) =>
                writer.WriteStringValue(value.ToString());
}

Then try to add convert to the property by JsonConverter Attribute.

public class Post
{
    [JsonConverter(typeof(GuidJsonConverter))]
    public Guid AuthorId { get; set; }

    public string Title { get; set; }
}

c# online

CodePudding user response:

I created a custom converter:

public sealed class JsonConverterGuid : System.Text.Json.Serialization.JsonConverter<Guid>
{
    public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TryGetGuid(out Guid value))
        {
            Console.WriteLine("guid");
            return value;
        }

        if (reader.TryGetString(out string str))
        {
            Console.WriteLine("string");
            return Guid.Parse(str);
        }

        throw new FormatException("The JSON value is not in a supported Guid format.");
    }

    public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value);
    }
}

public static class Ext
{
    public static bool TryGetString(this Utf8JsonReader je, out string parsed)
    {
        var(p, r) = je.TokenType switch
        {
            JsonTokenType.String => (je.GetString(), true),
            JsonTokenType.Null => (null, true),
            _ => (default, false)};
        parsed = p;
        return r;
    }
}

Maybe GUID without dashes isn't a standard, but I want to be compatible with Newtonsoft. I'm posting the answer, because someone might have the same error as I did.

and used it like this: https://dotnetfiddle.net/K9UXpb

  • Related