. NET-serialización JSON de enum como cadena


Tengo una clase que contiene una propiedad enum, y al serializar el objeto usando JavaScriptSerializer, mi resultado json contiene el valor entero de la enumeración en lugar de su string "nombre". ¿Hay alguna manera de obtener la enumeración como string en mi json sin tener que crear un JavaScriptConverter personalizado? Tal vez hay un atributo que podría decorar la definición enum, o propiedad del objeto, con?

Como ejemplo:

enum Gender { Male, Female }

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

Resultado json deseado:

{ "Age": 35, "Gender": "Male" }
Author: Chris Halcrow, 2010-03-14

20 answers

No hay ningún atributo especial que pueda usar. JavaScriptSerializer serializa enums a sus valores numéricos y no a su representación de cadena. Necesitará usar serialización personalizada para serializar enum como su nombre en lugar de su valor numérico.

Editar: Como señaló @OmerBakhari JSON.net cubre este caso de uso (a través del atributo [JsonConverter(typeof(StringEnumConverter))]) y muchos otros no manejados por los serializadores.net integrados. Aquí hay un enlace que compara las características y funcionalidades de la serializers .

 224
Author: Matt Dearing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-25 12:20:39

He encontrado que Json.NET proporciona la funcionalidad exacta que estoy buscando con un atributo StringEnumConverter:

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

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

Más detalles disponibles en StringEnumConverter documentación.

 1706
Author: Omer Bokhari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-06 17:23:16

Agregue lo siguiente a su global.asax para serialización JSON de enum de c# como cadena

  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
Author: Iggy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-09 18:06:33

@Iggy answer establece la serialización JSON de la enumeración de c # como cadena solo para ASP.NET (Web API y así).

Pero para que funcione también con la serialización ad hoc, agregue lo siguiente a su clase de inicio (como 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;
});

Más información sobre el Json.NET page

Además, para que su miembro enum sea serializado/deserializado hacia/desde un texto específico, use el

Sistema.Ejecución.Serialización.EnumMember

Atributo, así:

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

    [EnumMember(Value = "US/Alaska")] 
    USAlaska
}
 106
Author: Juri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-24 11:24:47

No pude cambiar el modelo de origen como en la respuesta superior (de @ob.), y no quería registrarlo globalmente como @Iggy. Así que combiné https://stackoverflow.com/a/2870420/237091 y @Iggy's https://stackoverflow.com/a/18152942/237091 para permitir la configuración del convertidor string enum durante el propio comando SerializeObject:

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
Author: Scott Stafford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:26

Esto se hace fácilmente agregando un ScriptIgnore atributo a la propiedad Gender, haciendo que no sea serializada, y añadiendo una propiedad GenderString que hace serializada:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}
 29
Author: Stephen Kennedy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-21 13:27:09

Esta versión de la respuesta de Stephen no cambia el nombre en el 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
Author: mheyman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:26

Aquí está la respuesta para newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
 21
Author: GuCa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-21 09:47:56

Aquí hay una solución simple que serializa una enumeración C# del lado del servidor a JSON y usa el resultado para rellenar un elemento <select> del lado del cliente. Esto funciona tanto para enumeraciones simples como para enumeraciones bitflag.

He incluido la solución de extremo a extremo porque creo que la mayoría de las personas que desean serializar una enumeración de C# a JSON probablemente también la usarán para llenar un desplegable <select>.

Aquí va:

Ejemplo Enum

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

Una enumeración compleja que utiliza OR bit a bit para generar un sistema de permisos. Así que no puedes confiar en el índice simple [0,1,2..] para el valor entero de la enumeración.

Lado del servidor-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);
};

El código anterior utiliza el framework NancyFx para manejar la solicitud Get. Utiliza el método helper de Nancy Response.AsJson(), pero no se preocupe, puede usar cualquier formateador JSON estándar, ya que la enumeración ya se ha proyectado en un tipo anónimo simple listo para serialización.

JSON generado

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

Lado Del Cliente - 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 Antes de

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

HTML Después de

<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
Author: biofractal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-22 14:13:31

La combinación de las respuestas de Omer Bokhari y uri es siempre mi solución, ya que los valores que quiero proporcionar son generalmente diferentes de lo que tengo en mi enumeración, especialmente que me gustaría poder cambiar mis enumeraciones si lo necesito.

Así que si alguien está interesado, es algo como esto:

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
Author: Ashkan Sirous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-16 10:52:58

Puede crear JsonSerializerSettings con la llamada a JsonConverter.SerializeObject como abajo:

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );
 11
Author: Yang Zhang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-17 12:29:49

También puede agregar un convertidor a su JsonSerializer si no desea usar el atributo JsonConverter:

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

Funcionará para cada enum que vea durante esa serialización.

 11
Author: JerryGoyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-13 13:04:35

Para. Net Core Web Api: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}
 8
Author: PeteGO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-30 22:47:24

Notó que no hay respuesta para la serialización cuando hay un atributo Description.

Aquí está mi implementación que soporta el atributo 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");
    }
}

Enumeración:

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

    // Will be serialized as "Applicable"
    Applicable
}

Uso:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }
 7
Author: Greg R Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-05 08:50:47

Esta es una vieja pregunta, pero pensé en contribuir por si acaso. En mis proyectos utilizo modelos separados para cualquier solicitud Json. Un modelo normalmente tendría el mismo nombre que el objeto de dominio con el prefijo "Json". Los modelos se mapean usando AutoMapper . Al hacer que el modelo json declare una propiedad de cadena que es una enumeración en la clase de dominio, AutoMapper resolverá su presentación de cadena.

En caso de que se lo pregunte, necesito modelos separados para las clases serializadas Json porque serializer viene con referencias circulares de lo contrario.

Espero que esto ayude a alguien.

 5
Author: Ales Potocnik Hahonina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-27 15:58:04

Puede usar un JavaScriptConverter para lograr esto con el JavaScriptSerializer incorporado. Al convertir su enumeración a un Uri, puede codificarla como una cadena.

He descrito cómo hacer esto para fechas, pero también se puede usar para enumeraciones.

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

 3
Author: Sebastian Markbåge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 10:29:30

En caso de que alguien encuentre lo anterior insuficiente, terminé conformándome con esta sobrecarga:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
 3
Author: hngr18,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-27 08:35:49

ASP.NET Camino del núcleo:

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
Author: user1407492,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-19 08:08:26

He reunido todas las piezas de esta solución usando la biblioteca Newtonsoft.Json. Corrige el problema de enumeración y también hace que el manejo de errores sea mucho mejor, y funciona en servicios alojados en IIS. Es bastante código, así que puedes encontrarlo en GitHub aquí: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

Tienes que añadir algunas entradas a tu Web.config para que funcione, puedes ver un archivo de ejemplo aqui: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config

 0
Author: Jon Grant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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
Author: Slava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-19 15:23:17