Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Customize Deserialization of a JSON enum in .NET?

I have the following sample C# code that is auto-genereated from an xsd using the svcutils.exe application.

    [DataContract]
    public enum Foo
    {
        [EnumMember(Value = "bar")]
        Bar = 1,

        [EnumMember(Value = "baz")]
        Baz = 2
    }

    [DataContract]
    public class UNameIt
    {
        [DataMember(Name = "id")]
        public long Id { get; private set; }

        [DataMember(Name = "name")]
        public string Name { get; private set; }

        [DataMember(Name = "foo")]
        public Foo Foo { get; private set; }
    }

The following is a unit test that attempts to deserialise a sample JSON document to the UNameIt class.

    [TestClass]
    public class JsonSerializer_Fixture
    {
        public const string JsonData = @"{ ""id"":123456,
                                           ""name"":""John Doe"",
                                           ""foo"":""Bar""}";

        [TestMethod]
        public void DataObjectSimpleParseTest()
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(UNameIt));

            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(JsonData));
            UNameIt dataObject = serializer.ReadObject(ms) as UNameIt;

            Assert.IsNotNull(dataObject);
            Assert.AreEqual(123456, dataObject.Id);
            Assert.AreEqual(Foo.Baz, dataObject.Foo);
        }
    }

Unfortunately, the test fails giving the following reason:

System.Runtime.Serialization.SerializationException: There was an error deserializing the object of type MyNamespace.Units.UNameIt. The value 'Bar' cannot be parsed as the type 'Int64'.

The test will pass if I update my JSON string to replace the string specifier for the Enum to an integer e.g.

public const string JsonData = @"{ ""id"":123456,
                                   ""name"":""John Doe"",
                                    ""foo"":""1""}";

I do not have the flexibility to the change the supplied JSON so I have to figure out how to convert the string Enum representation perhaps on serialisation. Ideally, I would like to facilitate this without having to change my autogenerate class because once I re-generate the class I would loose my changes.

I am wondering if it would be possible to extend the DataContractJsonSerializer to custom handle Enumerations? Or perhaps there is better way to do this?

like image 244
user989046 Avatar asked Jan 25 '12 08:01

user989046


People also ask

Can you serialize an enum C#?

Different Ways to Serialize Enum to String in C#Both native and Newtonsoft libraries provide a converter for this purpose, named as JsonStringEnumConverter and StringEnumConverter respectively. They also provide an attribute JsonConverterAttribute that we can use to serialize string-enum selectively.

How do you serialize an enum?

In order to serialize Enum, we take the help of ObjectMapper class. We use the writeValueAsString() method of ObjectMapper class for serializing Enum. If we serialize Enum by using the writeValueAsString() method, it will represent Java Enums as a simple string.

How do I deserialize a JSON file?

A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.


1 Answers

This behavior is by design. Here's a quote from the Enumerations and JSON paragraph on MSDN:

Enumeration member values are treated as numbers in JSON, which is different from how they are treated in data contracts, where they are included as member names.

Moreover the DataContractJsonSerializer will automatically serialize all enumerations, so the EnumMemberAttribute is actually ignored.

For a workaround, take a look at this answer on SO.

like image 168
Enrico Campidoglio Avatar answered Sep 28 '22 13:09

Enrico Campidoglio