JavaScriptSerializer - JSON serialization of enum as string

614,058

Solution 1

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 OmerBakhari: 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.

Solution 2

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.

Solution 3

Add the below to your global.asax for JSON serialization of c# enum as string

  HttpConfiguration config = GlobalConfiguration.Configuration;
            config.Formatters.JsonFormatter.SerializerSettings.Formatting =
                Newtonsoft.Json.Formatting.Indented;

            config.Formatters.JsonFormatter.SerializerSettings.Converters.Add
                (new Newtonsoft.Json.Converters.StringEnumConverter());

Solution 4

@Iggy answer sets JSON serialization of c# enum as string only for ASP.NET (Web API and so).

But to make it work also with ad hoc serialization, add following to your start class (like Global.asax Application_Start)

//convert Enums to Strings (instead of Integer) globally
JsonConvert.DefaultSettings = (() =>
{
    var settings = new JsonSerializerSettings();
    settings.Converters.Add(new StringEnumConverter { CamelCaseText = true });
    return settings;
});

More information on the Json.NET page

Additionally, to have your enum member to serialize/deserialize to/from specific text, use the

System.Runtime.Serialization.EnumMember

attribute, like this:

public enum time_zone_enum
{
    [EnumMember(Value = "Europe/London")] 
    EuropeLondon,

    [EnumMember(Value = "US/Alaska")] 
    USAlaska
}

Solution 5

I wasn't able to change the source model like in the top answer (of @ob.), and I didn't want to register it globally like @Iggy. So I combined https://stackoverflow.com/a/2870420/237091 and @Iggy's https://stackoverflow.com/a/18152942/237091 to allow setting up the string enum converter on during the SerializeObject command itself:

Newtonsoft.Json.JsonConvert.SerializeObject(
    objectToSerialize, 
    Newtonsoft.Json.Formatting.None, 
    new Newtonsoft.Json.JsonSerializerSettings()
    {
        Converters = new List<Newtonsoft.Json.JsonConverter> {
            new Newtonsoft.Json.Converters.StringEnumConverter()
        }
    })
Share:
614,058
Omer Bokhari
Author by

Omer Bokhari

Updated on May 11, 2022

Comments

  • Omer Bokhari
    Omer Bokhari almost 2 years

    I have a class that contains an enum property, and upon serializing the object using JavaScriptSerializer, my json result contains the integer value of the enumeration rather than its string "name". Is there a way to get the enum as a string in my json without having to create a custom JavaScriptConverter? Perhaps there's an attribute that I could decorate the enum definition, or object property, with?

    As an example:

    enum Gender { Male, Female }
    
    class Person
    {
        int Age { get; set; }
        Gender Gender { get; set; }
    }
    

    Desired JSON result:

    { "Age": 35, "Gender": "Male" }
    

    Ideally looking for answer with built-in .NET framework classes, if not possible alternatives (like Json.net) are welcome.

    • Stephen Kennedy
      Stephen Kennedy almost 9 years
      Change to which? The highest upvoted answer doesn't actually answer the question - yes it is useful in other contexts, hence the votes, but it is of no practicable use whatsoever if you are stuck with the MS JavaScriptSerializer, as essentially you are if using page methods and, most importantly, as required by the question. The accepted answer says its not possible. My answer whilst a bit of a hack gets the job done.
  • RredCat
    RredCat over 13 years
    Follow by link for description how to use it in asp.net mvc application james.newtonking.com/archive/2008/10/16/…
  • CAD bloke
    CAD bloke over 12 years
    Here is the link to that function: james.newtonking.com/projects/json/help/html/…
  • KCD
    KCD over 11 years
    I believe this is valid for the DataContractJsonSerializer not JavaScriptSerializer
  • ledragon
    ledragon about 11 years
    Nice to learn that feature of Automapper ;-) [ScriptIgnore] attribute will remove circular references
  • Ales Potocnik Hahonina
    Ales Potocnik Hahonina about 11 years
    Oh. Didn't know about the attribute. Thanks! Would you use that on your Pocos? I've resorted to using MetadataType definitions for any Poco attributes just to keep them clean. Would the attribute still work via meta data?
  • RredCat
    RredCat about 11 years
    Let me try to explain. This solution isn't correct according to design paters. You modified the model according to view purpose. But model has to contain data only and doesn't care about presentations. You have to move this functionality on the other layer.
  • Dima
    Dima almost 11 years
    Actually, Model is used to pass data from controller, ant it is controller, who does not care about presentation. Introduction of automated property (GenderString here) does not break controller, which still uses Gender property, but provides easy access for a view. Logical solution.
  • The Senator
    The Senator over 10 years
    Simple and solves the problem for me using native .NET framework serializers.
  • Iggy
    Iggy over 10 years
    HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter.SerializerSettings.Formattin‌​g = Newtonsoft.Json.Formatting.Indented; config.Formatters.JsonFormatter.SerializerSettings.Converter‌​s.Add (new Newtonsoft.Json.Converters.StringEnumConverter());
  • Mariano Desanze
    Mariano Desanze over 10 years
    @RredCat There is nothing wrong with having view-specific properties in the "view model". IMHO the mistake would be not to split the view model from the domain model: blogs.msdn.com/b/simonince/archive/2010/01/26/…
  • Daniel Gruszczyk
    Daniel Gruszczyk over 10 years
    best solution for me as I am not allowed to use 3rd party libraries (ISO complience issues)
  • MEMark
    MEMark over 10 years
    @RredCat, even if it were incorrect according to some pattern, the OP says nothing about this, so this is indeed a correct answer. (Even if I philosophically may agree with your point.)
  • sq33G
    sq33G over 10 years
    For some reason, I'm not getting this to work. Fiddler shows a stubborn 2 rather than 'Warning', even with this in place. Also - any reason why to change the Formatting to Indented?
  • Odys
    Odys about 10 years
    It is useful to note by default ASP.NET MVC doesn't use Json.Net as json serializer and one need to either extend Controller or manually override every serialization.
  • Greg Z.
    Greg Z. about 10 years
    The third line from this example was added to the App_start/webapiconfig.cs file and did a trick for me in an ASP.NET Web API 2.1 project to return strings for enum values in REST (json fomat) calls.
  • Bogdan
    Bogdan over 9 years
    this also woks nice if you have a property like this List<someEnumType>
  • Stephen Kennedy
    Stephen Kennedy over 9 years
    This isn't for the type of serialiser in the question of course. JavaScriptSerializer serialises everything which isn't ignored, whereas DataContractJsonSerializer requires DataMember attributes. Thanks for the shout out but please note you spelt my name wrong :)
  • crush
    crush over 9 years
    Is it possible to do this with the DataContractJsonSerializer?
  • user3285954
    user3285954 almost 9 years
    @Stephen Kennedy: Why keep both properties in this case? Why not have string Gender only?
  • Stephen Kennedy
    Stephen Kennedy almost 9 years
    @user3285954 GenderString is read only (no setter). You need to store the value somewhere. It could of course be a private property/field.
  • user3285954
    user3285954 almost 9 years
    @Stephen Kennedy The question still stands: what is the benefit of having both values in a view model if only the string is used?
  • Stephen Kennedy
    Stephen Kennedy almost 9 years
    @user3285954 It's a cheap way to achieve the required serialisation using the built-in JavaScriptSerializer, i.e. it answers the question. Only the string will be serialized so I really don't see the problem. If you want elegance use Json.Net; if you need a quick workaround to the issue posed and want to use asmx or page methods with the built-in serializer, here is the answer.
  • user3285954
    user3285954 almost 9 years
    @Stephen Kennedy How is creating an additional property and using an attribute cheaper than changing property type to string? I mean what is the benefit to store the same data in the same object twice when one of them is ignored? Not to mention that this requires an awkward name to avoid conflict.
  • Stephen Kennedy
    Stephen Kennedy almost 9 years
    @user3285954 The value is only stored once, as an enum, with the rationale that the enum property may be referenced elsewhere in the solution. It is also serialised only once, as a string, which is done on the fly. This solution has worked well for me and 26 upvoters. Feel free to modify the approach e.g. to a string property only if that suits you better (and see also myehman's variation of my answer). Just bear in mind this is a practical workaround for a slightly inadequate piece of MS functionality, not a design principle! I won't be commenting any further. Thanks.
  • Basic
    Basic almost 9 years
    Of course, deserializing using this method will cause problems since the property is readonly
  • Mike Mooney
    Mike Mooney almost 9 years
    The pedantically absurd bike-shedding in this comment thread is fascinating.
  • Mike Caron
    Mike Caron over 8 years
    The actual answer to @user3285954's question is that the enum is constrained to a limited set of values, while the string is not. Depending on whether you need to pass values back, this may or may not be sufficient.
  • Anestis Kivranoglou
    Anestis Kivranoglou about 8 years
    Is there a way to Set this property only per Request Scope?
  • BeemerGuy
    BeemerGuy almost 8 years
    @Fabzter -- your solution worked with me using Newtonsoft's Json
  • BrainSlugs83
    BrainSlugs83 over 7 years
    @AnestisKivranoglou just make use a custom json serializer per request with it's own settings.
  • BrainSlugs83
    BrainSlugs83 over 7 years
    @BornToCode Json.NET is the serializer that ASP.NET uses by default.
  • BornToCode
    BornToCode over 7 years
    @BrainSlugs83 - The question was about using JavaScriptSerializer, not Json.NET (and if you look at the revisions history you'll see that there was an edit to clarify that), if you use JavaScriptSerializer the attribute JsonConverter is not going to work.
  • user3791372
    user3791372 over 7 years
    the first serializer setting of indented is unrelated to the op question.
  • Poulad
    Poulad over 6 years
    Thank you! I was just looking for [EnumMember].
  • ᴍᴀᴛᴛ ʙᴀᴋᴇʀ
    ᴍᴀᴛᴛ ʙᴀᴋᴇʀ over 6 years
    You'll need references for System.Net.Http.Formatting, System.Web.Http and System.Web.Http.WebHost.
  • Seafish
    Seafish over 6 years
    You can customize the converter (say, for camelCase output): new StringEnumConverter { CamelCaseText = true }
  • infl3x
    infl3x over 6 years
    If this is the one from the Microsoft.AspNetCore.Mvc.Formatters.Json NuGet package, it seems to only be an extension method on IMvcCoreBuilder, not IMvcBuilder. So it's used like services.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));.
  • Peet
    Peet about 6 years
    Thank you for this answer, helped me a lot! If you want to define your enums in PascalCase, but you want it to be serialized in camelCase then you need to add true to your JsonConverter type like this: [JsonConverter(typeof(StringEnumConverter), true)]
  • Prolog
    Prolog over 5 years
    I was using JsonPropertyAttribute for enum members and it is working for simple deserializtion tasks. Sadly, during manual tweaks with JTokens it gets ignored. Happilly EnumMemberAttribute works like a charm. Thanks!
  • CMS
    CMS over 5 years
    as always Newtonsoft.Json does not disappoint, then i wonder why is XML still used 😌
  • Sbu
    Sbu about 5 years
    The constructor now takes a naming strategy type (the bool param camelCaseText being deprecated), so if you want e.g. camelCase : new StringEnumConverter(typeof(CamelCaseNamingStrategy))
  • Dirk Brockhaus
    Dirk Brockhaus almost 5 years
    This is a good solution for a current use case of mine: I don't want to change the serializers defaults and I have problems using attributes, because my properties are of type IList<EnumType>.
  • fiat
    fiat over 4 years
    The CamelCaseText property is now marked obsolete. New way to instantiate the converter: new StringEnumConverter(new CamelCaseNamingStrategy())
  • Alexei Levenkov
    Alexei Levenkov over 4 years
    Omer Bokhari: if you agree with my edit on the answer consider to flag all comments as "other: remove all comments as they are inlined in the post". (Definitely mark this as "no longer needed" when you read it).
  • ryanwebjackson
    ryanwebjackson almost 4 years
    "Json.NET is the serializer that ASP.NET uses by default" -- This was not true when the question was asked or answered. (but the most important thing is the clarity of the answer)
  • laventnc
    laventnc over 3 years
    still relatively new to .NET but I've been told to avoid try catch expressions for performance reasons. Wouldn't a serializer be a bad place to use one if that is the case?
  • Dusty
    Dusty over 3 years
    @laventnc The try...catch itself isn't going to impact performance, but if exception is raised, there's performance overhead for that. The point of this implementation is fault tolerance ... not allowing a single unknown enum value to prevent your entire JSON payload from deserializing. Compare the base StringEnumConveter: the exception would still be raised, but it will cause the whole deserialization process to fail (and its likely caught somewhere farther up the stack). Whether you need this kind of fault tolerance is an artifact of your use case(s).
  • developer learn999
    developer learn999 over 3 years
    the JsonConvert you place in ConfigureServices or in Configure in NET CORE 2?
  • John Washam
    John Washam about 3 years
    As @Bogdan mentioned, this was the fix for me to make a List<AnEnumType> property serialize with the string value of each Enum value instead of the number value.
  • Noman_1
    Noman_1 almost 3 years
    [JsonConverter(typeof(StringEnumConverter))] is for newtonsoft
  • jolySoft
    jolySoft almost 3 years
    Nice and clean.
  • Dean
    Dean almost 2 years
    The correct library to use here is actually: using System.Text.Json.Serialization;