Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JsonSerializer returns empty object instead of null

I'm using System.Text.Json 6.0.0 running on .NET 6. My problem is that when I try to deserialize my model the serializer returns an empty object instead of null (or throwing).

var stream = GetSomeStream();
var model=  await JsonSerializer.DeserializeAsync<MyModel>(stream, new JsonSerializerOptions()
{
// No options...
});
if (model == null || model != default)
{
    // Since it's an empty object this line will never be reached.
    return new BadRequestResult();
}

What I need is to determine if the deserialization went well or not. My model is a record, thus not having any methods or annotations. What's the best way to determine if the deserialization failed? In theory I could create a new instance of MyModel with all properties set to default and then compare the to objects, but it seems there should be a cleaner way to do it.

If I can avoid custom converters and other nugets that would be preferable.

Reproducable example:

    private static Stream CreateBody(object body)
    {
        var ms = new MemoryStream();
        var sw = new StreamWriter(ms);
        var json = System.Text.Json.JsonSerializer.Serialize(body);
        sw.Write(json);
        sw.Flush();
        ms.Position = 0;
        return ms;
    }

    // Either a record or a class... Same result.
    public record MyModel(Guid Id, string Name, int Age, Guid OtherGuid);

    [Test]
    public void WorkingSerialization()
    {
        var model = new MyModel() {Name = "name", Age = 2, Id = Guid.NewGuid(), OtherGuid = Guid.NewGuid()};
        var stream = CreateBody(model);
        var result = System.Text.Json.JsonSerializer.Deserialize<MyModel>(stream);
        result.Should().BeEquivalentTo(model);
    }

    [Test]
    public void NotWorkingSerialization()
    {
        var dummyModel = new {Foo = "bar"};
        var stream = CreateBody(dummyModel);
        // Should throw or return null.
        var result = System.Text.Json.JsonSerializer.Deserialize<MyModel>(stream);
        Assert.IsNull(result);
    }

I have already looked at:

  • https://github.com/DevBetterCom/DevBetter.JsonExtensions
  • https://github.com/dotnet/runtime/issues/37483
like image 788
smoksnes Avatar asked May 21 '26 22:05

smoksnes


1 Answers

Technically, the serialisation is working successfully. It's returning an empty object because none of the properties in the input stream matches a property in the output model.

One workaround is to add a constructor on your model to ensure it is initialised correctly

public class MyModel
{
    public MyModel(Guid id, string name, int age, Guid otherGuid)
    {
        if (id == Guid.Empty)
            throw new ArgumentNullException(nameof(id));

        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException(nameof(name));

        // More checks here...

        Id = id;
        Name = name;
        Age = age;
        OtherGuid = otherGuid;
    }
    
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public Guid OtherGuid { get; set; }
}
like image 136
DavidG Avatar answered May 23 '26 11:05

DavidG