JavaScriptSerializer - JSON-Serialisierung von Enum als Zeichenfolge

1161

Ich habe eine Klasse, die eine enumEigenschaft enthält , und beim Serialisieren des Objekts mit JavaScriptSerializerenthält mein json-Ergebnis den ganzzahligen Wert der Aufzählung und nicht den string"Namen". Gibt es eine Möglichkeit, die Aufzählung als stringin meinem JSON zu erhalten, ohne eine benutzerdefinierte erstellen zu müssen JavaScriptConverter? Vielleicht gibt es ein Attribut, mit dem ich die enumDefinition oder Objekteigenschaft dekorieren könnte ?

Als Beispiel:

enum Gender { Male, Female }

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

Gewünschtes json Ergebnis:

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

Idealerweise suchen Sie nach Antworten mit integrierten .NET Framework-Klassen. Wenn nicht möglich, sind Alternativen (wie Json.net) willkommen.

Omer Bokhari
quelle
8
Zu welchem ​​wechseln? Die am höchsten bewertete Antwort beantwortet die Frage nicht wirklich - ja, sie ist in anderen Kontexten nützlich, daher die Stimmen, aber sie ist überhaupt nicht praktikabel, wenn Sie mit dem MS JavaScriptSerializer nicht weiterkommen, wie Sie es im Wesentlichen tun, wenn Sie Seitenmethoden und verwenden vor allem, wie in der Frage gefordert. Die akzeptierte Antwort besagt, dass dies nicht möglich ist. Meine Antwort, während ein bisschen Hack den Job erledigt.
Stephen Kennedy

Antworten:

376

Nein, Sie können kein spezielles Attribut verwenden. JavaScriptSerializerserialisiert enumsauf ihre numerischen Werte und nicht auf ihre Zeichenfolgendarstellung. Sie müssten eine benutzerdefinierte Serialisierung verwenden, um den enumNamen anstelle des numerischen Werts zu serialisieren .


Wenn Sie JSON.Net statt verwenden können , JavaScriptSerializerals siehe Antwort auf diese Frage , die von OmerBakhari JSON.net deckt diesen Anwendungsfall (über das Attribut: [JsonConverter(typeof(StringEnumConverter))]) und viele andere nicht behandelt durch die eingebaute in .net Serializer. Hier ist ein Link zum Vergleich der Merkmale und Funktionen der Serializer .

Matt Dearing
quelle
7
@ Fabzter - Ihre Lösung funktionierte mit mir mit Newtonsofts Json
BeemerGuy
1
@BornToCode Json.NET ist der Serializer, den ASP.NET standardmäßig verwendet.
BrainSlugs83
12
@ BrainSlugs83 - Bei der Frage ging es um die Verwendung von JavaScriptSerializer, nicht um Json.NET (und wenn Sie sich den Revisionsverlauf ansehen, werden Sie feststellen, dass eine Änderung vorgenommen wurde, um dies zu verdeutlichen). Wenn Sie JavaScriptSerializer verwenden JsonConverter, funktioniert das Attribut nicht.
BornToCode
50
Bitte entfernen Sie dies als akzeptierte Antwort, da dies das Problem nicht löst. Die Antwort unten mit mehr als 1000 Upvotes reicht aus.
MHGameWork
könnte u Anwers mich
Yongqiang Chen
2101

Ich habe festgestellt, dass Json.NET genau die Funktionalität bietet, die ich mit einem StringEnumConverterAttribut suche :

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

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

Weitere Details finden Sie in der StringEnumConverterDokumentation .

Es gibt andere Möglichkeiten, diesen Konverter globaler zu konfigurieren:

  • enum selbst, wenn enum immer als Zeichenfolge serialisiert / deserialisiert werden soll:

    [JsonConverter(typeof(StringEnumConverter))]  
    enum Gender { Male, Female }
  • Falls jemand die Attributdekoration vermeiden möchte, können Sie den Konverter zu Ihrem JsonSerializer hinzufügen (vorgeschlagen von Bjørn Egil ):

    serializer.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); 

    und es funktioniert für jede Aufzählung, die es während dieser Serialisierung sieht (vorgeschlagen von Travis ).

  • oder JsonConverter (vorgeschlagen von Banane ):

    JsonConvert.SerializeObject(MyObject, 
        new Newtonsoft.Json.Converters.StringEnumConverter());

Darüber hinaus können Sie mithilfe des StringEnumConverter-Konstruktors (NamingStrategy, Boolean) steuern, ob und ob Zahlen noch akzeptiert werden .

Omer Bokhari
quelle
9
Folgen Sie dem Link, um eine Beschreibung der Verwendung in der asp.net mvc-Anwendung james.newtonking.com/archive/2008/10/16/… zu erhalten.
RredCat
2
Hier ist der Link zu dieser Funktion: james.newtonking.com/projects/json/help/html/…
CAD-
61
HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; config.Formatters.JsonFormatter.SerializerSettings.Converters.Add (neuer Newtonsoft.Json.Converters.StringEnumConverter ());
Iggy
1
Es ist nützlich zu beachten, dass ASP.NET MVC standardmäßig Json.Net nicht als JSON-Serializer verwendet und Controllerjede Serialisierung entweder erweitert oder manuell überschrieben werden muss.
Odys
2
Sie können den Konverter anpassen (z. B. für die camelCaseAusgabe):new StringEnumConverter { CamelCaseText = true }
Seafish
172

Fügen Sie Folgendes zu Ihrer global.asax für die JSON-Serialisierung von c # enum als Zeichenfolge hinzu

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

            config.Formatters.JsonFormatter.SerializerSettings.Converters.Add
                (new Newtonsoft.Json.Converters.StringEnumConverter());
Iggy
quelle
4
Aus irgendeinem Grund bekomme ich das nicht zum Laufen. Fiddler zeigt eher eine hartnäckige 2 als "Warnung", auch wenn diese vorhanden ist. Auch - ein Grund , warum sich ändert das Formattingzu Indented?
sq33G
5
Die dritte Zeile aus diesem Beispiel wurde der Datei App_start / webapiconfig.cs hinzugefügt und hat in einem ASP.NET Web API 2.1-Projekt einen Trick ausgeführt, um Zeichenfolgen für Aufzählungswerte in REST-Aufrufen (json fomat) zurückzugeben.
Greg Z.
1
Gibt es eine Möglichkeit, diese Eigenschaft nur pro Anforderungsbereich festzulegen?
Anestis Kivranoglou
@AnestisKivranoglou verwenden Sie einfach einen benutzerdefinierten JSON-Serializer pro Anfrage mit eigenen Einstellungen.
BrainSlugs83
3
Die erste Serializer-Einstellung von eingerückt hat nichts mit der Operationsfrage zu tun.
user3791372
153

@Iggy answer legt die JSON-Serialisierung von c # enum nur für ASP.NET (Web-API usw.) als Zeichenfolge fest.

Damit dies auch bei der Ad-hoc-Serialisierung funktioniert, fügen Sie Ihrer Startklasse Folgendes hinzu (z. B. 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;
});

Weitere Informationen finden Sie auf der Json.NET-Seite

Verwenden Sie außerdem die Option, damit Ihr Enum-Mitglied zu / von einem bestimmten Text serialisiert / deserialisiert

System.Runtime.Serialization.EnumMember

Attribut wie folgt:

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

    [EnumMember(Value = "US/Alaska")] 
    USAlaska
}
Juri
quelle
6
Vielen Dank! Ich habe nur gesucht [EnumMember].
Poulad
Die CamelCaseTextEigenschaft ist jetzt als veraltet markiert. Neue Art, den Konverter zu instanziieren:new StringEnumConverter(new CamelCaseNamingStrategy())
Fiat
Vielen Dank, machte meinen Tag! :)
Eldoïr
39

Ich konnte das Quellmodell nicht wie in der Top-Antwort (von @ob.) Ändern und wollte es nicht global wie @Iggy registrieren. Daher habe ich https://stackoverflow.com/a/2870420/237091 und @ Iggys https://stackoverflow.com/a/18152942/237091 kombiniert , um das Einrichten des String-Enum-Konverters während des SerializeObject-Befehls selbst zu ermöglichen:

Newtonsoft.Json.JsonConvert.SerializeObject(
    objectToSerialize, 
    Newtonsoft.Json.Formatting.None, 
    new Newtonsoft.Json.JsonSerializerSettings()
    {
        Converters = new List<Newtonsoft.Json.JsonConverter> {
            new Newtonsoft.Json.Converters.StringEnumConverter()
        }
    })
Scott Stafford
quelle
Dies ist auch schön, wenn Sie eine Eigenschaft wie diese haben. List <someEnumType>
Bogdan
34

Die Kombination der Antworten von Omer Bokhari und uri ist immer meine Lösung, da sich die Werte, die ich bereitstellen möchte, normalerweise von denen unterscheiden, die ich in meiner Aufzählung habe, insbesondere, dass ich meine Aufzählungen bei Bedarf ändern möchte.

Wenn also jemand interessiert ist, ist es ungefähr so:

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

class Person
{
    int Age { get; set; }
    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
Ashkan Sirous
quelle
1
Ich habe es JsonPropertyAttributefür Enum-Mitglieder verwendet und es funktioniert für einfache Deserialisierungsaufgaben. Leider wird es bei manuellen Optimierungen mit JTokens ignoriert. Happilly EnumMemberAttributewirkt wie ein Zauber. Vielen Dank!
Prolog
Das funktioniert mit JavaScriptSerializer?
Stephen Kennedy
31

Dies ist einfach zu bewerkstelligen, indem ScriptIgnoreder GenderEigenschaft ein Attribut hinzugefügt wird , wodurch sie nicht serialisiert wird, und eine GenderStringEigenschaft hinzugefügt wird , die serialisiert wird:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}
Stephen Kennedy
quelle
29
Lassen Sie mich versuchen zu erklären. Diese Lösung ist laut Designpattern nicht korrekt. Sie haben das Modell entsprechend dem Ansichtszweck geändert. Das Modell muss jedoch nur Daten enthalten und kümmert sich nicht um Präsentationen. Sie müssen diese Funktionalität auf die andere Ebene verschieben.
RredCat
4
Tatsächlich wird Model verwendet, um Daten vom Controller zu übergeben, und es ist der Controller, der sich nicht um die Präsentation kümmert. Die Einführung der automatisierten Eigenschaft (hier GenderString) unterbricht nicht den Controller, der weiterhin die Eigenschaft Gender verwendet, bietet jedoch einen einfachen Zugriff für eine Ansicht. Logische Lösung.
Dima
17
@RredCat Es ist nichts Falsches daran, ansichtsspezifische Eigenschaften im "Ansichtsmodell" zu haben. IMHO wäre der Fehler, das Ansichtsmodell nicht vom Domain-Modell zu trennen
Mariano Desanze
5
@RredCat, auch wenn es nach einem bestimmten Muster falsch war, sagt das OP nichts darüber, also ist dies in der Tat eine richtige Antwort. (Auch wenn ich Ihrem Standpunkt philosophisch zustimmen kann.)
MEMark
10
Das pedantisch absurde Bike-Shedding in diesem Kommentarthread ist faszinierend.
Mike Mooney
26

Diese Version von Stephens Antwort ändert den Namen im JSON nicht:

[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; 
        }
    }
}
Mheyman
quelle
3
Ich glaube, dies gilt für die DataContractJsonSerializernichtJavaScriptSerializer
KCD
Einfach und löst das Problem für mich mit nativen .NET Framework-Serialisierern.
Der Senator
Beste Lösung für mich, da ich keine Bibliotheken von Drittanbietern verwenden darf (ISO-Konformitätsprobleme)
Daniel Gruszczyk
Dies ist natürlich nicht für den Typ des Serialisierers in der Frage. JavaScriptSerializer serialisiert alles, was nicht ignoriert wird, während DataContractJsonSerializer DataMember-Attribute erfordert. Vielen Dank für den Ruf, aber bitte beachten Sie, dass Sie meinen Namen falsch geschrieben haben :)
Stephen Kennedy
25

Hier ist die Antwort für newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
GuCa
quelle
1
Vielen Dank für diese Antwort, hat mir sehr geholfen! Wenn Sie Ihre Aufzählungen in PascalCase definieren möchten, diese aber in camelCase serialisiert werden sollen, müssen Sie trueIhren JsonConverter-Typ wie folgt hinzufügen :[JsonConverter(typeof(StringEnumConverter), true)]
Peet
25

ASP.NET Core-Methode:

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

st1
quelle
funktioniert perfekt
DevJoe
16

Sie können Ihrem auch einen Konverter hinzufügen, JsonSerializerwenn Sie kein JsonConverterAttribut verwenden möchten :

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

Es funktioniert für jeden, den enumes während dieser Serialisierung sieht.

JerryGoyal
quelle
15

Hier ist eine einfache Lösung, die eine serverseitige C # -Aufzählung in JSON serialisiert und das Ergebnis zum Auffüllen eines clientseitigen <select>Elements verwendet. Dies funktioniert sowohl für einfache Aufzählungen als auch für Bitflag-Aufzählungen.

Ich habe die End-to-End-Lösung aufgenommen, da ich denke, dass die meisten Leute, die eine C # -Aufzählung in JSON serialisieren möchten, sie wahrscheinlich auch zum Ausfüllen eines <select>Dropdowns verwenden werden.

Hier geht:

Beispiel Enum

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

Eine komplexe Aufzählung, die bitweise ODERs verwendet, um ein Berechtigungssystem zu generieren. Sie können sich also nicht auf den einfachen Index [0,1,2 ..] für den ganzzahligen Wert der Aufzählung verlassen.

Serverseite - 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);
};

Der obige Code verwendet das NancyFX-Framework, um die Get-Anforderung zu verarbeiten. Es verwendet die Response.AsJson()Hilfsmethode von Nancy - aber keine Sorge, Sie können jeden Standard-JSON-Formatierer verwenden, da die Aufzählung bereits in einen einfachen anonymen Typ projiziert wurde, der für die Serialisierung bereit ist.

JSON generiert

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

Client-Seite - 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 vor

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

HTML nach

<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>
Biofractal
quelle
13

Für ASP.Net-Kern Fügen Sie Ihrer Startklasse einfach Folgendes hinzu:

JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });
Yahya Hussein
quelle
1
Dies funktioniert für alle Versionen, nicht nur für den Kern.
Bikeman868
11

Sie können JsonSerializerSettings mit dem Aufruf von JsonConverter.SerializeObject wie folgt erstellen:

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

Es wurde festgestellt, dass es keine Antwort auf die Serialisierung gibt, wenn ein Description-Attribut vorhanden ist.

Hier ist meine Implementierung, die das Description-Attribut unterstützt.

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");
    }
}

Aufzählung:

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

    // Will be serialized as "Applicable"
    Applicable
}

Verwendungszweck:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }
Greg R Taylor
quelle
10

Für .Net Core: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}
PeteGO
quelle
2
Wenn dies das aus dem Microsoft.AspNetCore.Mvc.Formatters.JsonNuGet-Paket ist, scheint es nur eine Erweiterungsmethode zu sein IMvcCoreBuilder, nicht IMvcBuilder. Also wird es wie verwendet services.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));.
infl3x
9

In .net Core 3 ist dies jetzt mit den in System.Text.Json integrierten Klassen möglich:

var person = new Person();
// Create and add a converter which will use the string representation instead of the numeric value.
var stringEnumConverter = new System.Text.Json.Serialization.JsonStringEnumConverter();
JsonSerializerOptions opts = new JsonSerializerOptions();
opts.Converters.Add(stringEnumConverter);
// Generate json string.
var json = JsonSerializer.Serialize<Person>(person, opts);

So konfigurieren Sie JsonStringEnumConvertermit Attributdekoration für die bestimmte Eigenschaft:

using System.Text.Json.Serialization;

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

Wenn Sie die Aufzählung immer als Zeichenfolge konvertieren möchten, setzen Sie das Attribut in die Aufzählung selbst.

[JsonConverter(typeof(JsonStringEnumConverter))] 
enum Gender { Male, Female }
Björn
quelle
9

Asp.Net Core 3 mit System.Text.Json

public void ConfigureServices(IServiceCollection services)
{

    services
        .AddControllers()
        .AddJsonOptions(options => 
           options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())
        );

    //...
 }
Serj-Tm
quelle
8

Nur für den Fall, dass jemand das oben Genannte für unzureichend hält, habe ich mich mit dieser Überlastung abgefunden:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
hngr18
quelle
Dies ist eine gute Lösung für einen aktuellen Anwendungsfall von mir: Ich möchte die Standardeinstellungen des Serialisierers nicht ändern und habe Probleme bei der Verwendung von Attributen, da meine Eigenschaften vom Typ IList <EnumType> sind.
Dirk Brockhaus
5

Dies ist eine alte Frage, aber ich dachte, ich würde nur für den Fall einen Beitrag leisten. In meinen Projekten verwende ich separate Modelle für alle Json-Anfragen. Ein Modell hat normalerweise denselben Namen wie ein Domänenobjekt mit dem Präfix "Json". Modelle werden mit AutoMapper zugeordnet . Wenn das JSON-Modell eine Zeichenfolgeeigenschaft deklariert, die eine Aufzählung der Domänenklasse darstellt, wird AutoMapper in die Zeichenfolgenpräsentation aufgelöst.

Für den Fall, dass Sie sich fragen, benötige ich separate Modelle für serialisierte Json-Klassen, da der eingebaute Serializer ansonsten Zirkelverweise enthält.

Hoffe das hilft jemandem.

Ales Potocnik Hahonina
quelle
Schön, diese Funktion von Automapper zu lernen ;-) [ScriptIgnore] -Attribut entfernt
Zirkelverweise
1
Oh. Wusste nichts über das Attribut. Vielen Dank! Würden Sie das auf Ihrem Pocos verwenden? Ich habe auf MetadataType-Definitionen für alle Poco-Attribute zurückgegriffen, um sie sauber zu halten. Würde das Attribut weiterhin über Metadaten funktionieren?
Ales Potocnik Hahonina
3

Sie können tatsächlich einen JavaScriptConverter verwenden, um dies mit dem integrierten JavaScriptSerializer zu erreichen. Indem Sie Ihre Enumeration in eine Uri konvertieren, können Sie sie als Zeichenfolge codieren.

Ich habe beschrieben, wie dies für Datumsangaben gemacht wird, aber es kann auch für Aufzählungen verwendet werden. Benutzerdefiniertes DateTime-JSON-Format für .NET JavaScriptSerializer .

Sebastian Markbåge
quelle
Sehr interessante Lösung! Danke für das Teilen.
Oliver
1

Ich bin mir nicht sicher, ob dies noch relevant ist, aber ich musste direkt in eine JSON-Datei schreiben und kam auf die folgenden Punkte, um mehrere Stackoverflow-Antworten zusammenzusetzen

public class LowercaseJsonSerializer
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new LowercaseContractResolver()
    };

    public static void Serialize(TextWriter file, object o)
    {
        JsonSerializer serializer = new JsonSerializer()
        {
            ContractResolver = new LowercaseContractResolver(),
            Formatting = Formatting.Indented,
            NullValueHandling = NullValueHandling.Ignore
        };
        serializer.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
        serializer.Serialize(file, o);
    }

    public class LowercaseContractResolver : DefaultContractResolver
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            return Char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1);
        }
    }
}

Es stellt sicher, dass alle meine JSON-Schlüssel gemäß den JSON-Regeln in Kleinbuchstaben geschrieben sind. Formatiert es sauber eingerückt und ignoriert Nullen in der Ausgabe. Durch Hinzufügen eines StringEnumConverter werden auch Aufzählungen mit ihrem Zeichenfolgenwert gedruckt.

Persönlich finde ich das das sauberste, was ich mir vorstellen kann, ohne das Modell mit Anmerkungen verschmutzen zu müssen.

Verwendungszweck:

    internal void SaveJson(string fileName)
    {
        // serialize JSON directly to a file
        using (StreamWriter file = File.CreateText(@fileName))
        {
            LowercaseJsonSerializer.Serialize(file, jsonobject);
        }
    }
kenny
quelle
0

Ich habe alle Teile dieser Lösung mithilfe der Newtonsoft.JsonBibliothek zusammengestellt. Es behebt das Enum-Problem und verbessert die Fehlerbehandlung erheblich. Es funktioniert in von IIS gehosteten Diensten. Es ist ziemlich viel Code, also finden Sie ihn auf GitHub hier: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

Sie müssen einige Einträge zu Ihrem hinzufügen Web.config, damit es funktioniert. Eine Beispieldatei finden Sie hier: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config

Jon Grant
quelle
0

Und für VB.net habe ich folgende Werke gefunden:

Dim sec = New Newtonsoft.Json.Converters.StringEnumConverter()
sec.NamingStrategy() = New Serialization.CamelCaseNamingStrategy

Dim JSON_s As New JsonSerializer
JSON_s.Converters.Add(sec)

Dim jsonObject As JObject
jsonObject = JObject.FromObject(SomeObject, JSON_s)
Dim text = jsonObject.ToString

IO.File.WriteAllText(filePath, text)
Benjamin Swedlove
quelle
0

Eine etwas zukunftssicherere Option

Angesichts der gleichen Frage stellten wir fest, dass wir eine benutzerdefinierte Version von benötigen StringEnumConverter, um sicherzustellen, dass unsere Enum-Werte im Laufe der Zeit erweitert werden können, ohne auf der deserialisierenden Seite katastrophal zu brechen (siehe Hintergrund unten). Verwendung derSafeEnumConverter Folgende verwenden, kann die Deserialisierung auch dann abgeschlossen werden, wenn die Nutzdaten einen Wert für die Aufzählung enthalten, für den keine benannte Definition vorliegt. Dies entspricht eher der Funktionsweise der Int-zu-Enum-Konvertierung.

Verwendungszweck:

[SafeEnumConverter]
public enum Colors
{
    Red,
    Green,
    Blue,
    Unsupported = -1
}

oder

[SafeEnumConverter((int) Colors.Blue)]
public enum Colors
{
    Red,
    Green,
    Blue
}

Quelle:

public class SafeEnumConverter : StringEnumConverter
{
    private readonly int _defaultValue;

    public SafeEnumConverter()
    {
        // if you've been careful to *always* create enums with `0` reserved
        // as an unknown/default value (which you should), you could use 0 here. 
        _defaultValue = -1;
    }

    public SafeEnumConverter(int defaultValue)
    {
        _defaultValue = defaultValue;
    }

    /// <summary>
    /// Reads the provided JSON and attempts to convert using StringEnumConverter. If that fails set the value to the default value.
    /// </summary>
    /// <returns>The deserialized value of the enum if it exists or the default value if it does not.</returns>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
        catch
        {
            return Enum.Parse(objectType, $"{_defaultValue}");
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return base.CanConvert(objectType) && objectType.GetTypeInfo().IsEnum;
    }
}

Hintergrund

Als wir uns die Verwendung von StringEnumConverteranschauten, hatten wir das Problem, dass wir auch Passivität für Fälle benötigten, in denen ein neuer Aufzählungswert hinzugefügt wurde, aber nicht jeder Kunde sofort von dem neuen Wert wusste. In diesen Fällen StringEnumConverterlöst das mit Newtonsoft JSON gepackte Programm einen JsonSerializationExceptionähnlichen Fehler aus wie "Fehler beim Konvertieren des Werts SomeString in den Typ EnumType", und dann schlägt der gesamte Deserialisierungsprozess fehl. Dies war ein Deal Breaker für uns, denn selbst wenn der Kunde vorhatte, den nicht verstandenen Immobilienwert zu ignorieren / zu verwerfen, musste er dennoch in der Lage sein, den Rest der Nutzlast zu deserialisieren!

Staubig
quelle
-2
        Person p = new Person();
        p.Age = 35;
        p.Gender = Gender.Male;
        //1.  male="Male";
        string male = Gender.Male.ToString();

        p.Gender = Gender.Female;

        //2.  female="Female";
        string female = Enum.GetName(typeof(Gender), p.Gender);

        JObject jobj = new JObject();
        jobj["Age"] = p.Age;
        jobj["Gender"] = male;
        jobj["Gender2"] = female;

        //you result:  josn= {"Age": 35,"Gender": "Male","Gender2": "Female"}
        string json = jobj.ToString();
Zilong
quelle
-5
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]  
);
Slava
quelle