.NET - la sérialisation JSON de enum comme une chaîne de caractères

j'ai une classe qui contient une propriété enum , et après avoir sérialisé l'objet en utilisant JavaScriptSerializer , mon résultat json contient la valeur entière de l'énumération plutôt que son string "nom". Est-il un moyen pour obtenir l'enum comme un string dans mon json sans avoir à créer un personnalisé JavaScriptConverter ? Peut-être qu'il y a un attribut avec lequel je pourrais décorer la définition enum , ou la propriété objet?

comme exemple:

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }
    Gender Gender { get; set; }
}

résultat JSON désiré:

{ "Age": 35, "Gender": "Male" }
888
demandé sur Chris Halcrow 2010-03-14 08:18:56

20 réponses

Non il n'y a pas d'attribut spécial que vous pouvez utiliser. JavaScriptSerializer sérialise enums à leurs valeurs numériques et non à leur représentation de chaîne. Vous auriez besoin d'utiliser la sérialisation personnalisée pour sérialiser le enum comme son nom au lieu de la valeur numérique.

Edit: Comme le souligne @OmerBakhari JSON.net couvre ce cas d'utilisation (via l'attribut [JsonConverter(typeof(StringEnumConverter))] ) et bien d'autres non traités par les sérialiseurs .net intégrés. voici un lien comparant les caractéristiques et les fonctionnalités des sérialiseurs .

224
répondu Matt Dearing 2017-09-25 12:20:39

j'ai trouvé que Json.NET fournit la fonctionnalité exacte que je cherche avec un attribut StringEnumConverter :

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

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

plus de détails sur StringEnumConverter documentation .

1706
répondu Omer Bokhari 2017-02-06 17:23:16

ajoutez ce qui suit à votre global.asax pour la sérialisation JSON en c# enum en tant que chaîne de caractères

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

            config.Formatters.JsonFormatter.SerializerSettings.Converters.Add
                (new Newtonsoft.Json.Converters.StringEnumConverter());
151
répondu Iggy 2013-08-09 18:06:33

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

mais pour que cela fonctionne aussi avec la sérialisation ad hoc, ajoutez la suite à votre classe start (comme 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;
});

plus d'information sur le Json.NET page

de plus, pour que votre membre enum sérialise/désérialise à partir d'un texte spécifique, utilisez le

Système

.Runtime.Sérialisation.EnumMember

attribut, comme ceci:

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

    [EnumMember(Value = "US/Alaska")] 
    USAlaska
}
106
répondu Juri 2014-11-24 11:24:47

Je n'ai pas pu changer le modèle source comme dans la réponse du haut (de @ob.), et je ne voulais pas l'enregistrer globalement comme @Iggy. Donc j'ai combiné https://stackoverflow.com/a/2870420/237091 et de @Iggy https://stackoverflow.com/a/18152942/237091 pour permettre la mise en place du convertisseur de chaîne enum pendant la commande SerializeObject elle-même:

Newtonsoft.Json.JsonConvert.SerializeObject(
    objectToSerialize, 
    Newtonsoft.Json.Formatting.None, 
    new Newtonsoft.Json.JsonSerializerSettings()
    {
        Converters = new List<Newtonsoft.Json.JsonConverter> {
            new Newtonsoft.Json.Converters.StringEnumConverter()
        }
    })
29
répondu Scott Stafford 2017-05-23 11:47:26

cela se fait facilement en ajoutant un attribut ScriptIgnore à la propriété Gender , ce qui la rend non sérialisée, et en ajoutant une propriété GenderString qui fait obtenir sérialisée:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}
29
répondu Stephen Kennedy 2018-02-21 13:27:09

Cette version de Stephen réponse ne pas modifier le nom dans le JSON:

[DataContract(
    Namespace = 
       "http://schemas.datacontract.org/2004/07/Whatever")]
class Person
{
    [DataMember]
    int Age { get; set; }

    Gender Gender { get; set; }

    [DataMember(Name = "Gender")]
    string GenderString
    {
        get { return this.Gender.ToString(); }
        set 
        { 
            Gender g; 
            this.Gender = Enum.TryParse(value, true, out g) ? g : Gender.Male; 
        }
    }
}
26
répondu mheyman 2017-05-23 11:47:26

Voici la réponse pour newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
21
répondu GuCa 2015-04-21 09:47:56

Voici une solution simple qui sérialise un C# enum côté serveur vers JSON et utilise le résultat pour peupler un élément <select> côté client. Cela fonctionne pour les deux enums simples et bitflag enums.

j'ai inclus la solution de bout en bout parce que je pense que la plupart des gens qui veulent sérialiser un C# enum à JSON l'utiliseront probablement aussi pour remplir un <select> drop-down.

va Ici:

exemple Enum

public enum Role
{
    None = Permission.None,
    Guest = Permission.Browse,
    Reader = Permission.Browse| Permission.Help ,
    Manager = Permission.Browse | Permission.Help | Permission.Customise
}

un enum complexe qui utilise des ORs bitwise pour générer un système de permissions. Donc, vous ne pouvez pas compter sur le simple index [0,1,2..] pour la valeur entière de l'enum.

Côté Serveur - C#

Get["/roles"] = _ =>
{
    var type = typeof(Role);
    var data = Enum
        .GetNames(type)
        .Select(name => new 
            {
                Id = (int)Enum.Parse(type, name), 
                Name = name 
            })
        .ToArray();

    return Response.AsJson(data);
};

le code ci-dessus utilise le framework NancyFX pour gérer la requête Get. Il utilise la méthode D'aide Response.AsJson() de Nancy - mais ne vous inquiétez pas, vous pouvez utiliser n'importe quel JSON standard formater comme l'enum a déjà été projeté dans un type anonyme simple prêt pour la sérialisation.

a Généré JSON

[
    {"Id":0,"Name":"None"},
    {"Id":2097155,"Name":"Guest"},
    {"Id":2916367,"Name":"Reader"},
    {"Id":4186095,"Name":"Manager"}
]

Côté Client-CoffeeScript

fillSelect=(id, url, selectedValue=0)->
    $select = $ id
    $option = (item)-> $ "<option/>", 
        {
            value:"#{item.Id}"
            html:"#{item.Name}"
            selected:"selected" if item.Id is selectedValue
        }
    $.getJSON(url).done (data)->$option(item).appendTo $select for item in data

$ ->
    fillSelect "#role", "/roles", 2916367

HTML avant

<select id="role" name="role"></select>

HTML après

<select id="role" name="role">
    <option value="0">None</option>
    <option value="2097155">Guest</option>
    <option value="2916367" selected="selected">Reader</option>
    <option value="4186095">Manager</option>
</select>
13
répondu biofractal 2014-09-22 14:13:31

la combinaison des réponses D'Omer Bokhari et uri est également ma solution puisque les valeurs que je veux fournir est généralement différent de ce que j'ai dans mon enum spécialement que je voudrais être en mesure de changer mes enums si j'ai besoin.

Donc si quelqu'un est intéressé, c'est quelque chose comme ceci:

public enum Gender
{
   [EnumMember(Value = "male")] 
   Male,
   [EnumMember(Value = "female")] 
   Female
}

class Person
{
    int Age { get; set; }
    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
12
répondu Ashkan Sirous 2017-08-16 10:52:58

vous pouvez créer JsonSerializerSettings avec l'appel à JsonConverter.SerializeObject comme ci-dessous:

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );
11
répondu Yang Zhang 2015-06-17 12:29:49

Vous pouvez également ajouter un convertisseur à votre JsonSerializer si vous ne voulez pas utiliser JsonConverter attribut:

string SerializedResponse = JsonConvert.SerializeObject(
     objToSerialize, 
     new Newtonsoft.Json.Converters.StringEnumConverter()
); 

il fonctionnera pour chaque enum qu'il voit pendant cette sérialisation.

11
répondu JerryGoyal 2016-07-13 13:04:35

Pour L'Api Web De .Net Core: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}
8
répondu PeteGO 2017-04-30 22:47:24

a remarqué qu'il n'y a pas de réponse pour la sérialisation lorsqu'il y a un attribut Description.

Voici mon implémentation qui supporte l'attribut Description.

public class CustomStringEnumConverter : Newtonsoft.Json.Converters.StringEnumConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Type type = value.GetType() as Type;

        if (!type.IsEnum) throw new InvalidOperationException("Only type Enum is supported");
        foreach (var field in type.GetFields())
        {
            if (field.Name == value.ToString())
            {
                var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                writer.WriteValue(attribute != null ? attribute.Description : field.Name);

                return;
            }
        }

        throw new ArgumentException("Enum not found");
    }
}

Enum:

public enum FooEnum
{
    // Will be serialized as "Not Applicable"
    [Description("Not Applicable")]
    NotApplicable,

    // Will be serialized as "Applicable"
    Applicable
}

Utilisation:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }
7
répondu Greg R Taylor 2016-03-05 08:50:47

c'est une vieille question mais j'ai pensé que je pourrais contribuer juste au cas où. Dans mes projets, j'utilise des modèles séparés pour toutes les requêtes Json. Un modèle aurait généralement le même nom que l'objet du domaine avec le préfixe "Json". Les modèles sont mappés en utilisant AutoMapper . En ayant le modèle JSON déclarer une propriété de chaîne de caractères qui est un enum sur la classe de domaine, AutoMapper résoudra à sa présentation de chaîne de caractères.

Dans le cas où vous vous demandez, j'ai besoin de modèles séparés pour Json sérialisé cours parce intégré sérialiseur vient avec des références circulaires autrement.

J'espère que ça aidera quelqu'un.

5
répondu Ales Potocnik Hahonina 2012-03-27 15:58:04

vous pouvez réellement utiliser un JavaScriptConverter pour accomplir cela avec le JavaScriptSerializer intégré. En convertissant votre enum en Uri, vous pouvez l'encoder comme une chaîne.

, j'ai décrit comment faire pour les dates, mais il peut être utilisé pour les énumérations.

http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization /

3
répondu Sebastian Markbåge 2011-12-28 10:29:30

juste au cas où quelqu'un trouverait ce qui précède insuffisant, j'ai fini par régler avec cette surcharge:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
3
répondu hngr18 2016-06-27 08:35:49

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

1
répondu user1407492 2018-06-19 08:08:26

j'ai assemblé toutes les pièces de cette solution en utilisant la bibliothèque Newtonsoft.Json . Il corrige le problème d'enum et améliore également la gestion des erreurs, et fonctionne dans les services hébergés par IIS. C'est beaucoup de code, donc vous pouvez le trouver sur GitHub ici: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

Vous devez ajouter des entrées à votre Web.config pour le faire fonctionner, vous pouvez voir une exemple de fichier ici: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config

0
répondu Jon Grant 2016-07-12 10:45:29
new JavaScriptSerializer().Serialize(  
    (from p   
    in (new List<Person>() {  
        new Person()  
        {  
            Age = 35,  
            Gender = Gender.Male  
        }  
    })  
    select new { Age =p.Age, Gender=p.Gender.ToString() }  
    ).ToArray()[0]  
);
-4
répondu Slava 2016-04-19 15:23:17