. NET - JSON serializacja enum jako string

Mam klasę, która zawiera właściwość enum i po serializacji obiektu za pomocą JavaScriptSerializer, mój wynik json zawiera wartość całkowitą wyliczenia, a nie jego string "Nazwa". Czy istnieje sposób, aby uzyskać enum jako string w moim json bez konieczności tworzenia niestandardowego JavaScriptConverter? Może jest jakiś atrybut, którym mógłbym ozdobić enum definicję lub właściwość obiektu?

Jako przykład:

enum Gender { Male, Female }

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

Pożądany wynik json:

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

20 answers

Nie istnieje żaden specjalny atrybut, którego możesz użyć. JavaScriptSerializer serializuje enums do ich wartości liczbowych, a nie do ich reprezentacji łańcuchowej. Aby serializować enum jako nazwę zamiast wartości numerycznej, należy użyć niestandardowej serializacji.

Edit: Jak zauważył @OmerBakhari JSON.net obejmuje ten przypadek użycia (poprzez atrybut [JsonConverter(typeof(StringEnumConverter))]) i wiele innych nie obsługiwanych przez wbudowane serializery. NET. Oto link porównujący funkcje i funkcjonalności serializery .

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-25 12:20:39

I have found that Json.NET dostarcza dokładną funkcjonalność, której szukam z atrybutem StringEnumConverter:

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

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

Więcej szczegółów na stronie StringEnumConverter Dokumentacja .

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-06 17:23:16

Dodaj poniżej do swojej globalnej.asax dla serializacji JSON c # enum jako 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());
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-09 18:06:33

@Iggy answer ustawia serializację JSON w c# enum jako ciąg znaków Tylko dla ASP.NET (Web API i tak).

Ale aby to działało również z serializacją ad hoc, dodaj following do swojej klasy startowej (jak 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;
});

Więcej informacji na Json.NET Strona

Dodatkowo, aby Twój członek enum mógł serializować / deserializować do / z określonego tekstu, użyj

System.Runtime.Serializacja.EnumMember

Atrybut, TAK:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-24 11:24:47

Nie byłem w stanie zmienić modelu źródłowego jak w górnej odpowiedzi (z @ob.), a ja nie chciałem rejestrować go globalnie jak @Iggy. Więc połączyłem https://stackoverflow.com/a/2870420/237091 i @ Iggy ' s https://stackoverflow.com/a/18152942/237091 aby umożliwić włączenie konwertera ciągu znaków enum podczas samego polecenia 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:26

Można to łatwo zrobić, dodając ScriptIgnore atrybut do właściwości Gender, co powoduje, że nie jest serializowana, i dodanie właściwości GenderString, która robi otrzymuje serializację:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 13:27:09

Ta wersja odpowiedzi Stephena nie zmienia nazwy w 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:26

Oto odpowiedź dla 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-21 09:47:56

Oto proste rozwiązanie, które serializuje C# enum po stronie serwera do JSON i używa wyniku do wypełnienia elementu po stronie klienta <select>. Działa to zarówno dla enum prostych, jak i enum bitflag.

Dodałem rozwiązanie end-to-end, ponieważ myślę, że większość ludzi, którzy chcą serializować C# enum do JSON, prawdopodobnie będzie go używać do wypełnienia <select> rozwijanej listy.

Idzie:

Przykład Enum

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

Złożone enum, które wykorzystuje bitowe or do generowania system uprawnień. Więc nie można polegać na prostym indeksie [0,1,2..] dla wartości całkowitej enum.

Strona Serwera-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);
};

Powyższy kod wykorzystuje framework NancyFX do obsługi żądania Get. Używa metody pomocniczej Response.AsJson() Nancy - ale nie martw się, możesz użyć dowolnego standardowego formatera JSON, ponieważ enum zostało już rzutowane do prostego anonimowego typu gotowego do serializacji.

Wygenerowany JSON

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

Strona Klienta - 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 przed

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

HTML po

<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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-22 14:13:31

Kombinacja Omer Bokhari i odpowiedzi Uriego jest zawsze moim rozwiązaniem, ponieważ wartości, które chcę podać, zwykle różnią się od tego, co mam w moim enum, szczególnie, że chciałbym móc zmienić moje enum, jeśli muszę.

Więc jeśli ktoś jest zainteresowany, to jest to coś takiego:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-16 10:52:58

Możesz utworzyć JsonSerializerSettings za pomocą wywołania JsonConverter.SerializeObject jak poniżej:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-17 12:29:49

Możesz również dodać konwerter do swojego JsonSerializer, jeśli nie chcesz używać atrybutu JsonConverter:

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

To będzie działać dla każdego enum widzi podczas tej serializacji.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 13:04:35

Dla. 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-30 22:47:24

Zauważyłem, że nie ma odpowiedzi na serializację, gdy istnieje atrybut opisu.

Oto moja implementacja, która wspiera atrybut 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
}

Użycie:

[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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-05 08:50:47

To stare pytanie, ale pomyślałem, że na wszelki wypadek się dołożymy. W moich projektach używam osobnych modeli dla dowolnych żądań Json. Model ma zazwyczaj taką samą nazwę jak obiekt domain z przedrostkiem "Json". Modele są mapowane za pomocą AutoMapper . Jeśli model json deklaruje właściwość string, która jest klasą enum na domenie, AutoMapper rozwiąże swoją prezentację string.

Jeśli się zastanawiasz, potrzebuję osobnych modeli dla klas serializowanych Json, ponieważ wbudowane serializer wymyśla odniesienia okrągłe inaczej.

Mam nadzieję, że to komuś pomoże.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-27 15:58:04

Możesz użyć Javascriptconvertera, aby to osiągnąć za pomocą wbudowanego Javascriptserializera. Konwertując swój enum na Uri możesz zakodować go jako ciąg znaków.

Opisałem, jak to zrobić dla dat, ale może być również używany do wyliczeń.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-28 10:29:30

Na wszelki wypadek, gdyby ktoś uznał powyższe za niewystarczające, skończyło się na tym przeciążeniu:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-27 08:35:49

ASP.NET Droga Podstawowa:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-19 08:08:26

Zebrałem wszystkie fragmenty tego rozwiązania za pomocą biblioteki Newtonsoft.Json. Rozwiązuje problem enum, a także znacznie poprawia obsługę błędów i działa w usługach hostowanych IIS. Jest to dość dużo kodu, więc możesz go znaleźć na Githubie tutaj: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

Musisz dodać kilka wpisów do swojego Web.config aby go uruchomić, możesz zobaczyć przykładowy plik proszę.: 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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-19 15:23:17