c# deserialize - Sérialisation JSON d'enum sous forme de chaîne





newtonsoft mapper (17)


Je n'ai pas été capable de changer le modèle source comme dans la meilleure réponse (de @ob.), Et je ne voulais pas l'enregistrer globalement comme @Iggy. J'ai donc combiné https://stackoverflow.com/a/2870420/237091 et @ https://stackoverflow.com/a/18152942/237091 d'Iggy 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()
        }
    })

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

Par exemple:

enum Gender { Male, Female }

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

Résultat json désiré:

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



C'est une vieille question mais je pensais que je contribuerais au cas où. Dans mes projets, j'utilise des modèles séparés pour toutes les demandes JSON. Un modèle aurait généralement le même nom que l'objet domaine avec le préfixe "Json". Les modèles sont mappés à l'aide d' AutoMapper . En ayant le modèle json déclare une propriété de chaîne qui est une énumération sur la classe de domaine, AutoMapper résoudra à sa présentation de chaîne.

Dans le cas où vous vous posez la question, j'ai besoin de modèles séparés pour les classes sérialisées Json, car le sérialiseur intégré contient des références circulaires.

J'espère que cela aide quelqu'un.




Cela est facilement fait en ajoutant un attribut ScriptIgnore à la propriété Gender , en provoquant qu'il ne soit pas sérialisé, et en ajoutant une propriété GenderString qui est sérialisée:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}



Voici une solution simple qui sérialise une énumération C # côté serveur vers JSON et utilise le résultat pour remplir un élément <select> côté client. Cela fonctionne à la fois pour les enums simples et les enum bits.

J'ai inclus la solution de bout en bout parce que je pense que la plupart des personnes qui souhaitent sérialiser une enumère C # en JSON l'utiliseront probablement pour remplir une liste déroulante <select> .

Voici:

Exemple Enum

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

Une énumération complexe qui utilise des OR au niveau du bit pour générer un système d'autorisations. Vous ne pouvez donc pas compter sur l'index simple [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'assistance Response.AsJson() de Nancy - mais ne vous inquiétez pas, vous pouvez utiliser n'importe quel formateur JSON standard car l'énumération a déjà été projetée dans un simple type anonyme prêt pour la sérialisation.

JSON généré

[
    {"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>



Remarqué qu'il n'y a pas de réponse pour la sérialisation quand 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
}

Usage:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }



J'ai rassemblé toutes les pièces de cette solution en utilisant la bibliothèque Newtonsoft.Json . Il corrige le problème enum et améliore également la gestion des erreurs, et cela fonctionne dans les services hébergés 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 quelques entrées à votre Web.config pour le faire fonctionner, vous pouvez voir un exemple de fichier ici: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config




Ajoutez ci-dessous à votre global.asax pour la sérialisation JSON de c # enum sous forme de chaîne

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

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



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

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

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




Cette version de la answer de Stephen ne change pas 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; 
        }
    }
}



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

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );



Vous pouvez réellement utiliser un JavaScriptConverter pour accomplir ceci avec JavaScriptSerializer intégré. En convertissant votre énumération en Uri, vous pouvez l'encoder sous forme de chaîne.

J'ai décrit comment faire cela pour les dates mais il peut aussi être utilisé pour les énumérations.

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




La combinaison d'Omer Bokhari et des réponses d'Uri est toujours ma solution puisque les valeurs que je veux fournir sont généralement différentes de ce que j'ai dans mon énumération, spécialement que j'aimerais pouvoir changer mes énumérations si j'en ai besoin.

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

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

class Person
{
    int Age { get; set; }
    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}



Pour .Net Core Web Api: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}



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())



Voici la réponse pour newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

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



La réponse @Iggy définit la sérialisation JSON de c # enum en tant que chaîne uniquement pour ASP.NET (API Web et ainsi de suite).

Mais pour que cela fonctionne aussi avec une sérialisation ad hoc, ajoutez les suivantes à votre classe de démarrage (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'informations sur la page Json.NET

De plus, pour que votre membre enum puisse sérialiser / désérialiser vers / depuis un texte spécifique, utilisez le

System.Runtime.Serialization.EnumMember

attribut, comme ceci:

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

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



Si le JSON est avec padding, il s'agira de l' application/jsonp . Si le JSON est sans remplissage, il s'agira de l' application/json .

Pour traiter les deux, il est recommandé d'utiliser: 'application / javascript' sans se soucier de savoir si c'est avec ou sans remplissage.





c# asp.net json enums javascriptserializer