Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json Serialization of UnitsNet shows much more data than is in my class

I have created a .net core console app to play around and explore UnitsNet. In this app I have a class Person and instantiate it, populate it and use Json.NET to serialise that object before printing it out to the console.

My issue is that the JSON output includes a lot more properties than what I have in my Person class.

Dotnet Fiddle example

Ideally my JSON output would be similar to the below example instead of whats output by the Fiddle linked above.

{
"Acceleration": {
    "Value": 12.0,
    "Unit": 3,
    }
},
"Age": 42,
"BodyMass": {
    "StonePounds": {
    "Stone": 12.0,
    "Pounds": 5.0
    },
},
"Height": {
    "FeetInches": {
    "Feet": 5.0,
    "Inches": 10.0
    },
},
"Name": "Davey Jones",
"TopSpeed": {
    "MilesPerHour": 7.0,
}
}

There is a UnitsNet.Serialization.Json package available, but I'm not sure if the answer is in there, Json.NET or somewhere else.

Any pointers in the right direction would be much appreciated, and as this is my 1st Stack Overflow question any feedback regarding the post itself would be cool as well.

like image 413
Rhodri Avatar asked Oct 15 '25 18:10

Rhodri


1 Answers

The properties you are seeing in your JSON are the get-only properties of Assembly, Mass, Length and so on, which include get-only conversions to other units of the same type. Json.NET serializes get-only properties by default, which is why they are included. Since you don't want them, UnitsNetJsonConverter.cs from https://www.nuget.org/packages/UnitsNet.Serialization.JsonNet should eliminate them:

var settings = new JsonSerializerSettings
{
    Converters = { new UnitsNetJsonConverter() },
};
string json = JsonConvert.SerializeObject(person, Formatting.Indented, settings);

You can see some examples of using this converter in UnitsNetJsonConverterTests.cs written by angularsen, e.g.:

public class UnitsNetJsonConverterTests
{
    private readonly JsonSerializerSettings _jsonSerializerSettings;

    protected UnitsNetJsonConverterTests()
    {
        _jsonSerializerSettings = new JsonSerializerSettings {Formatting = Formatting.Indented};
        _jsonSerializerSettings.Converters.Add(new UnitsNetJsonConverter());
    }

    private string SerializeObject(object obj)
    {
        return JsonConvert.SerializeObject(obj, _jsonSerializerSettings).Replace("\r\n", "\n");
    }

    private T DeserializeObject<T>(string json)
    {
        return JsonConvert.DeserializeObject<T>(json, _jsonSerializerSettings);
    }

    public class Serialize : UnitsNetJsonConverterTests
    {
// Snip 
        [Fact]
        public void Mass_ExpectConstructedValueAndUnit()
        {
            Mass mass = Mass.FromPounds(200);
            var expectedJson = "{\n  \"Unit\": \"MassUnit.Pound\",\n  \"Value\": 200.0\n}";

            string json = SerializeObject(mass);

            Assert.Equal(expectedJson, json);
        }

// Snip 

Note that the JSON expected for Mass.FromPounds(200) is

{
  "Unit": "MassUnit.Pound",
  "Value": 200.0
}

Which is concise and lacks any unneeded properties.

Finally, do be aware of this documentation note:

Serialization

UnitsNet.Serialization.JsonNet (nuget, src, tests) for JSON.NET

Important! We cannot guarantee backwards compatibility, although we will strive to do that on a "best effort" basis and bumping the major nuget version when a change is necessary.

The base unit of any unit should be treated as volatile as we have changed this several times in the history of this library already. Either to reduce precision errors of common units or to simplify code generation. An example is Mass, where the base unit was first Kilogram as this is the SI unit of mass, but in order to use powershell scripts to generate milligrams, nanograms etc. it was easier to choose Gram as the base unit of Mass.

like image 195
dbc Avatar answered Oct 18 '25 08:10

dbc