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.JsonPropertyInfo
1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader) at System.Text.Json.Serialization.Converters.ObjectDefaultConverter
1.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.JsonConverter
1.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](ReadOnlySpan
1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable1 actualByteCount) at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan
1 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; }
}
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