JavaScriptSerializer - JSON serialization of enum as string

后端 未结 27 1700
耶瑟儿~
耶瑟儿~ 2020-11-22 03:22

I have a class that contains an enum property, and upon serializing the object using JavaScriptSerializer, my json result contains the integer valu

相关标签:
27条回答
  • 2020-11-22 04:19

    A slightly more future-proof option

    Facing the same question, we determined that we needed a custom version of StringEnumConverter to make sure that our enum values could expand over time without breaking catastrophically on the deserializing side (see background below). Using the SafeEnumConverter below allows deserialization to finish even if the payload contains a value for the enum that does not have a named definition, closer to how int-to-enum conversion would work.

    Usage:

    [SafeEnumConverter]
    public enum Colors
    {
        Red,
        Green,
        Blue,
        Unsupported = -1
    }
    

    or

    [SafeEnumConverter((int) Colors.Blue)]
    public enum Colors
    {
        Red,
        Green,
        Blue
    }
    

    Source:

    public class SafeEnumConverter : StringEnumConverter
    {
        private readonly int _defaultValue;
    
        public SafeEnumConverter()
        {
            // if you've been careful to *always* create enums with `0` reserved
            // as an unknown/default value (which you should), you could use 0 here. 
            _defaultValue = -1;
        }
    
        public SafeEnumConverter(int defaultValue)
        {
            _defaultValue = defaultValue;
        }
    
        /// <summary>
        /// Reads the provided JSON and attempts to convert using StringEnumConverter. If that fails set the value to the default value.
        /// </summary>
        /// <returns>The deserialized value of the enum if it exists or the default value if it does not.</returns>
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            try
            {
                return base.ReadJson(reader, objectType, existingValue, serializer);
            }
            catch
            {
                return Enum.Parse(objectType, $"{_defaultValue}");
            }
        }
    
        public override bool CanConvert(Type objectType)
        {
            return base.CanConvert(objectType) && objectType.GetTypeInfo().IsEnum;
        }
    }
    

    Background

    When we looked at using the StringEnumConverter, the problem we had is that we also needed passivity for cases when a new enum value was added, but not every client was immediately aware of the new value. In these cases, the StringEnumConverter packaged with Newtonsoft JSON throws a JsonSerializationException similar to "Error converting value SomeString to type EnumType" and then the whole deserialization process fails. This was a deal breaker for us, because even if the client planned on ignoring/discarding the property value that it didn't understand, it still needed to be capable of deserializing the rest of the payload!

    0 讨论(0)
  • 2020-11-22 04:20

    I have found that Json.NET provides the exact functionality I'm looking for with a StringEnumConverter attribute:

    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;
    
    [JsonConverter(typeof(StringEnumConverter))]
    public Gender Gender { get; set; }
    

    More details at available on StringEnumConverter documentation.

    There are other places to configure this converter more globally:

    • enum itself if you want enum always be serialized/deserialized as string:

      [JsonConverter(typeof(StringEnumConverter))]  
      enum Gender { Male, Female }
      
    • In case anyone wants to avoid attribute decoration, you can add the converter to your JsonSerializer (suggested by Bjørn Egil):

      serializer.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); 
      

      and it will work for every enum it sees during that serialization (suggested by Travis).

    • or JsonConverter (suggested by banana):

      JsonConvert.SerializeObject(MyObject, 
          new Newtonsoft.Json.Converters.StringEnumConverter());
      

    Additionally you can control casing and whether numbers are still accepted by using StringEnumConverter(NamingStrategy, Boolean) constructor.

    0 讨论(0)
  • 2020-11-22 04:21

    ASP.NET Core way:

    public class Startup
    {
      public IServiceProvider ConfigureServices(IServiceCollection services)
      {
        services.AddMvc().AddJsonOptions(options =>
        {
          options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
        });
      }
    }
    

    https://gist.github.com/regisdiogo/27f62ef83a804668eb0d9d0f63989e3e

    0 讨论(0)
提交回复
热议问题