Serializing enums as strings using System.Text.Json library in .NET Core 3.0

.NET Core 3.0 uses the System.Text.Json API by default for JSON serialization operations. Prior versions of .NET Core relied on JSON.NET, a third party library developed by Newtonsoft and the framework team decided to create a brand new library that can make use of the latest features in the language and the framework.

The new library has got support for all the new features that got introduced in the latest version of C#. And this was one of the main reasons behind the development of the new library because implementing these changes in JSON.NET meant a significant rewrite.

While serializing an object into JSON using the new library we can control various options such as casing, indentation, etc, but one notable omission is the support for enums by default. If you try to serialize an enum in .NET Core 3.0 with the default library, it will convert it into an integer value instead of the name of the enum.
For example, let consider the following model and see if what happens when we serialize it using the System.Text.Json library

public enum AddressType
{        
    HomeAddress,
    OfficeAddress,
    CommunicationAddress
    }

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public AddressType CommunicationPreference { get; set; }
}

and when you serialize it using the serialize method

List employees = new List{
    new Employee{
        FirstName = "Amal",
        LastName ="Dev",
        CommunicationPreference = AddressType.HomeAddress
    },
    new Employee{
        FirstName = "Dev",
        LastName ="D",
        CommunicationPreference = AddressType.CommunicationAddress
    },
    new Employee{
        FirstName = "Tris",
        LastName ="Tru",
        CommunicationPreference = AddressType.OfficeAddress
    }
}

JsonSerializer.Serialize(employees);

it will produce an output like the one given below

[ 
   { 
      "FirstName":"Amal",
      "LastName":"Dev",
      "CommunicationPreference":0
   },
   { 
      "FirstName":"Dev",
      "LastName":"D",
      "CommunicationPreference":2
   },
   { 
      "FirstName":"Tris",
      "LastName":"Tru",
      "CommunicationPreference":1
   }
]

If you look closely at the output string, the CommunicationPreference property has integer values instead of the names. In some scenarios, say if you are trying to give it as an output of an API method call it is not desirable to give back these integer values which can be meaningless. To overcome this, you can make use of a converter available in the library to do the conversion for you. To use this, instantiate an object of the JsonSerializerOptions and specify the converter there. And when you call the serialize method, pass this object also into that method as shown below

JsonSerializerOptions options = new JsonSerializerOptions{
    Converters ={
        new JsonStringEnumConverter()
    }
};

JsonSerializer.Serialize(employees, options);

Now the generated output will be

[
   {
      "FirstName":"Amal",
      "LastName":"Dev",
      "CommunicationPreference":"HomeAddress"
   },
   {
      "FirstName":"Dev",
      "LastName":"D",
      "CommunicationPreference":"CommunicationAddress"
   },
   {
      "FirstName":"Tris",
      "LastName":"Tru",
      "CommunicationPreference":"OfficeAddress"
   }
]

You will see now that our property is correctly displaying the names of the enums which is done automatically by the converter we added. By default, the library converts the strings to Pascal Case instead of the camelCase which is the most widely used format in JSON. You can control this behavior by specifying the format while hooking up the converter to the serializer

JsonSerializerOptions options = new JsonSerializerOptions{
    Converters ={
        new JsonStringEnumConverter( JsonNamingPolicy.CamelCase)
    },
    
};

And now, the output will be

[
   {
      "FirstName":"Amal",
      "LastName":"Dev",
      "CommunicationPreference":"homeAddress"
   },
   {
      "FirstName":"Dev",
      "LastName":"D",
      "CommunicationPreference":"communicationAddress"
   },
   {
      "FirstName":"Tris",
      "LastName":"Tru",
      "CommunicationPreference":"officeAddress"
   }
]

Deserializing Enums as Strings

We can use the same converter for doing deserialization also. If we try to deserialize a incoming payload that contains a string value instead of integer value for an enum the compiler value will throw JSON exception

string emp="[{\"FirstName\":\"Amal\",\"LastName\":\"Dev\",\"CommunicationPreference\":\"HomeAddress\"},{\"FirstName\":\"Dev\",\"LastName\":\"D\",\"CommunicationPreference\":\"CommunicationAddress\"},{\"FirstName\":\"Tris\",\"LastName\":\"Tru\",\"CommunicationPreference\":\"OfficeAddress\"}]";
Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to JsonTextApi.AddressType. Path: $[0].CommunicationPreference

But, if provide an integer value instead of string for the enum, the serializer will deserialize it as expected If you want to use the string value, then add the converter while calling the Deserialize method as we did for the serialization operation.

JsonSerializerOptions options = new JsonSerializerOptions{
    Converters ={
        new JsonStringEnumConverter( JsonNamingPolicy.CamelCase)
    },

};

JsonSerializer.Deserialize<List>(emp,options).ForEach(x=> Console.WriteLine($"{x.FirstName} {x.LastName}, {x.CommunicationPreference}"));

Output

Amal Dev, HomeAddress
Dev D, CommunicationAddress
Tris Tru, OfficeAddress

Part 1 : Serializing and Deserializing Json in .NET Core 3.0 using System.Text.Json API

Part 2: Step-By-Step Guide to Serialize and Deserialize JSON Using System.Text.Json

Part 3: Avoid conversion errors by using Custom Converters in System.Text.Json API


No Comments

Add a Comment