Deserialize Specific Enum into System.Enum in JSON.Net

Deserializing Enums C#

Is is possible to dynamically deserialize my enum string into enums?

If you are building a Web API project on dotnet-core, the solution in the blog you linked to works great, although I would use the standard System.Text.Json library (since core 3.0):

using System.Text.Json.Serialization;

namespace Foobar
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Foo
{
Bar = 0,
Baz = 1
}
}

This will convert the enum Foo.Bar into "Bar" on the client, and "Bar" -> Foo.Bar on the server.

Is there a way to keep my enums separate? I feel like a super long list of enum error codes is not very clean or maintainable.

I don't know if I can answer this part yet, because it looks like you've already done that with your class structure. I am confused about whether the code you gave is your goal or your current code.


For more on serialization and deserialization of enums, check out this post.

deserialize json with array of enum

TL/DR: You have two basic problems here:

  1. .NET Core 3.0+ has a new built-in JSON serializer System.Text.Json, and you are mixing up attributes and classes between this new serializer and Json.NET. This is very easy to do when both are installed because they share some class names, such as JsonSerializer and JsonConverter.

  2. The new serializer is used by default but does not yet support serialization of enums as strings with custom value names; see System.Text.Json: How do I specify a custom name for an enum value? for details.

The easiest way to solve your problem is to switch back to Json.NET as shown here and use attributes, converters and namespaces exclusively from this serializer.

First let's break down the differences and similarities between the two serializers:

  1. System.Text.Json:

    • Built into .NET Core 3.0+ automatically and used for JSON serialization by ASP.NET Core 3.0+ by default.

    • Namespaces System.Text.Json and System.Text.Json.Serialization.

    • Classes including System.Text.Json.Serialization.JsonConverter, System.Text.Json.Serialization.JsonConverter<T> and System.Text.Json.JsonSerializer.

    • Attributes including System.Text.Json.Serialization.JsonPropertyNameAttribute, System.Text.Json.Serialization.JsonConverterAttribute and System.Text.Json.Serialization.JsonExtensionDataAttribute.

    • Serialization of enums as strings is supported by System.Text.Json.Serialization.JsonStringEnumConverter, however renaming via attributes is not implemented.

      See this answer to System.Text.Json: How do I specify a custom name for an enum value? for potential workarounds.

  2. Json.NET:

    • A 3rd-party library that can be used for serialization in ASP.NET Core 3.0+ by adding a NuGet reference to Microsoft.AspNetCore.Mvc.NewtonsoftJson and then calling AddNewtonsoftJson() in Startup.ConfigureServices.

      For details see this answer to Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0? by poke.

    • Namespaces including Newtonsoft.Json, Newtonsoft.Json.Converters, Newtonsoft.Json.Linq and Newtonsoft.Json.Serialization among others.

    • Classes including Newtonsoft.Json.JsonConverter, Newtonsoft.Json.JsonConverter<T> and Newtonsoft.Json.JsonSerializer

    • Attributes including Newtonsoft.Json.JsonPropertyAttribute, Newtonsoft.Json.JsonConverterAttribute and Newtonsoft.Json.JsonExtensionDataAttribute among others.

    • Serialization of enums as renamed strings is supported automatically by Newtonsoft.Json.Converters.StringEnumConverter when the EnumMemberAttribute attribute is applied.

With this in mind, which serializer are you using in your code? Since you helpfully included the namespaces in your question, we can check:

using System.Text.Json.Serialization; // System.Text.Json
using Newtonsoft.Json; // Json.NET

namespace Assignment_1
{
public class MyRequest
{
//...
[JsonProperty( // JsonProperty from Newtonsoft
"changeTypes",
ItemConverterType = typeof(JsonStringEnumConverter)// JsonStringEnumConverter from System.Text.Json
)]
public AppGlobals.BoardSymbols[] GameBoard { get; set; }
}
}

So as you can see, you are mixing up attributes from Newtonsoft with converters from System.Text.Json, which isn't going to work. (Perhaps you selected the namespaces from a "Resolve -> using ..." right-click in Visual Studio?)

So, how to resolve the problem? Since Json.NET supports renaming of enum values out of the box, the easiest way to resolve your problem is to use this serializer. While possibly not as performant as System.Text.Json it is much more complete and full-featured.

To do this, remove the namespaces System.Text.Json.Serialization and System.Text.Json and references to the type JsonStringEnumConverter from your code, and modify MyRequest and BoardSymbols as follows:

using System.Runtime.Serialization;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json;

namespace Assignment_1
{
public class MyRequest
{
//...
[Required]
[MinLength(9)]
[MaxLength(9)]
[JsonProperty("changeTypes")] // No need to add StringEnumConverter here since it's already applied to the enum itself
public AppGlobals.BoardSymbols[] GameBoard { get; set; }
}
}

namespace AppGlobals
{
[JsonConverter(typeof(StringEnumConverter))]
public enum BoardSymbols
{
[EnumMember(Value = "X")]
First = 'X',
[EnumMember(Value = "O")]
Second = 'O',
[EnumMember(Value = "?")]
EMPTY = '?'
}
}

Then NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson and in Startup.ConfigureServices call AddNewtonsoftJson():

services.AddMvc()
.AddNewtonsoftJson();

Or if you prefer to use StringEnumConverter globally:

services.AddMvc()
.AddNewtonsoftJson(o => o.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()));

Do take note of the following comment from the docs

Note: If the AddNewtonsoftJson method isn't available, make sure that you installed the Microsoft.AspNetCore.Mvc.NewtonsoftJson package. A common error is to install the Newtonsoft.Json package instead of the Microsoft.AspNetCore.Mvc.NewtonsoftJson package.

Mockup fiddle here.

Json.NET serialize ListSystem.Enum and back to concrete types

The MainTheme as a simple string cannot be converted to an Enum. You should parse it using something like

BonusMusic enum = (BonusMusic)Enum.Parse(typeof(BonusMusic), "MainTheme");

Maybe you can implement a JSON custom serializer that could parse the values that come in the Bonuses array

You can check this JSON.NET Implementing Custom Serialization

Regards.

How do I deserialize an array of enum using Json.Net?

The StringEnumConverter expects only a single enumeration value. Because ChangeTypes is an array, you need to annotate the property a little differently to make it work.

Try this instead:

[JsonProperty("changeTypes", ItemConverterType=typeof(StringEnumConverter))]
public ChangeType[] ChangeTypes { get; set; }

Deserialize a JSON string integer to an Enum in ASP.NET Core

From How to customize property names and values with System.Text.Json - Enum as string.

By default, System.Text.Json convert enum from integer, but in you case "0" is a string. You need specify a converter to convert enum from string like :

public void ConfigureServices(IServiceCollection services)
{

services.AddControllers().AddJsonOptions(o =>
{
o.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
}

JavaScriptSerializer - JSON serialization of enum as string

No there is no special attribute you can use. JavaScriptSerializer serializes enums to their numeric values and not their string representation. You would need to use custom serialization to serialize the enum as its name instead of numeric value.


If you can use JSON.Net instead of JavaScriptSerializer than see answer on this question provided by Omer Bokhari: JSON.net covers this use case (via the attribute [JsonConverter(typeof(StringEnumConverter))]) and many others not handled by the built in .net serializers. Here is a link comparing features and functionalities of the serializers.

JSON deserialization with enum types

Your JSON properties are all strings and so they can only be deserialized to a String, while Enum values are actually integers.

You should be able to change your JSON to the following and it'll deserialize just fine

{
"Items": [
{
"ID": "1",
"Name": "Basic Sword",
"ItemType": 2,
"SlotType": 8
},
{
"ID": "2",
"Name": "Advanced Sword",
"ItemType": 2,
"SlotType": 8
},
{
"ID": "3",
"Name": "Leather Chest",
"ItemType": 1,
"SlotType": 2
}
]}

Update

At the time of writing this it had slipped my mind that StringEnumConverter existed. If you would like to retain readable names in your JSON model

[Serializable]
public class EquipementItem
{
public enum ItemTypes
{
None,
Armor,
Weapon
}

public enum SlotTypes
{
Head,
Shoulders,
Chest,
Bracers,
Gloves,
Waist,
Legs,
Boots,
Weapon
}

public int ID { get; set; }

public string Name { get; set; }

[JsonConverter(typeof(StringEnumConverter))]
public ItemTypes ItemType { get; set; }

[JsonConverter(typeof(StringEnumConverter))]
public SlotTypes SlotType { get; set; }
}

Newtonsoft JSON of Dictionary to list of different Enums

Newtonsoft serializes Enum default to their numeric value. And then it has no idea how to serialize that numeric value back to Enum. You can use an attribute on your Enum to serialize them to string value (so that your data transfer object is understandable) but to deserialize back to an object you have to implement your own JsonConverter.

It's easier to work with more easily serializable data types.

C# Enum deserialization with Json.Net: Error converting value to type

Let's say we have the following json string:

[
{
"Name": "abc",
"MyEnumValue": "Type1"
},
{
"Name": "abcd",
"MyEnumValue": "Type2"
},
{
"Name": "abcde",
"MyEnumValue": "Type3"
} ,
{
"Name": "abcdef",
"MyEnumValue": "Type4"
}
]

and the following class and enum:

public class MyClass
{
public string Name { get; set; }

public MyEnum MyEnumValue { get; set; }
}

public enum MyEnum
{
Type1,
Type2,
Type3
}

As it can be noticed, the json string array contains item (the last one), that cannot be correctly mapped to the MyEnum. To avoid deserialization errors you can use the following code snippet:

static void Main(string[] args)
{
var serializationSettings = new JsonSerializerSettings
{
Error = HandleDeserializationError
};

var lst = JsonConvert.DeserializeObject<List<MyClass>>(jsonStr, serializationSettings);
}

public static void HandleDeserializationError(object sender, ErrorEventArgs errorArgs)
{
errorArgs.ErrorContext.Handled = true;
var currentObj = errorArgs.CurrentObject as MyClass;

if (currentObj == null) return;
currentObj.MyEnumValue = MyEnum.Type2;
}

where the jsonStr variable is the posted json string above. In the above code sample, if MyEnumValue cannot be correctly interpreted, it is set to a default value of Type2.

Example: https://dotnetfiddle.net/WKd2Lt



Related Topics



Leave a reply



Submit