JavaScriptSerializer - การทำให้เป็นอนุกรม JSON ของ enum เป็นสตริง


1160

ฉันมีคลาสที่มีenumคุณสมบัติและเมื่อซีเรียลไลซ์วัตถุที่ใช้JavaScriptSerializerผลลัพธ์ json ของฉันมีค่าจำนวนเต็มของการแจงนับมากกว่าstring"ชื่อ" ของมัน มีวิธีในการรับ enum stringใน json ของฉันโดยไม่ต้องสร้างเองJavaScriptConverterหรือไม่ อาจมีแอตทริบิวต์ที่ฉันสามารถตกแต่งenumคำจำกัดความหรือคุณสมบัติของวัตถุด้วย?

ตัวอย่างเช่น:

enum Gender { Male, Female }

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

ผลลัพธ์ json ที่ต้องการ:

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

การหาคำตอบด้วยคลาสเฟรมเวิร์ก. NET แบบบิวด์อินหากไม่มีทางเลือกที่เป็นไปได้ (เช่น Json.net)


8
เปลี่ยนเป็นไหน คำตอบที่ได้รับการโหวตสูงสุดนั้นไม่ได้ตอบคำถามจริง ๆ - ใช่มันมีประโยชน์ในบริบทอื่น ๆ ดังนั้นการลงคะแนน แต่ก็ไม่มีประโยชน์ใด ๆ หากคุณติดอยู่กับ MS JavaScriptSerializer เช่นเดียวกับที่คุณใช้วิธีการของหน้าเว็บและ ที่สำคัญที่สุดคือตามที่คำถามต้องการ คำตอบที่ยอมรับว่าเป็นไปไม่ได้ คำตอบของฉันในขณะที่การแฮ็กเล็กน้อยทำให้งานเสร็จ
สตีเฟ่นเคนเนดี้

คำตอบ:


376

ไม่มีไม่มีแอตทริบิวต์พิเศษที่คุณสามารถใช้ได้ JavaScriptSerializerซีเรียลenumsไลซ์เป็นค่าตัวเลขไม่ใช่การแทนค่าสตริง คุณจะต้องใช้การทำให้เป็นอันดับแบบกำหนดเองเพื่อทำให้อนุกรมenumเป็นชื่อแทนค่าตัวเลข


หากคุณสามารถใช้ JSON.Net แทนที่จะJavaScriptSerializerเห็น คำตอบสำหรับคำถามนี้ที่จัดทำโดยOmerBakhari : JSON.net ครอบคลุมกรณีการใช้งานนี้ (ผ่านแอททริบิวต์[JsonConverter(typeof(StringEnumConverter))]) และอื่น ๆ อีกมากมายที่ไม่ได้รับการจัดการโดย. serializer ภายในสุทธิ นี่คือลิงค์เปรียบเทียบคุณสมบัติและฟังก์ชันการทำงานของซีเรียลไลเซอร์


7
@Fabzter - โซลูชันของคุณทำงานกับฉันโดยใช้ Newtonsoft's Json
BeemerGuy

1
@BornToCode Json.NET เป็น serializer ที่ ASP.NET ใช้ตามค่าเริ่มต้น
BrainSlugs83

12
@ BrainSlugs83 - คำถามเกี่ยวกับการใช้ JavaScriptSerializer ไม่ใช่ Json.NET (และหากคุณดูที่ประวัติการแก้ไขคุณจะเห็นว่ามีการแก้ไขเพื่อชี้แจงให้ชัดเจน) หากคุณใช้ JavaScriptSerializer แอตทริบิวต์JsonConverterนั้นจะไม่ทำงาน
BornToCode

50
โปรดลบสิ่งนี้เป็นคำตอบที่ยอมรับเนื่องจากไม่สามารถแก้ปัญหาได้คำตอบด้านล่างที่มีการโหวตมากกว่า 1,000 ครั้ง
MHGameWork

คุณช่วยฉันได้ไหม
Yongqiang Chen

2101

ฉันได้พบว่าJson.NETมีฟังก์ชั่นที่แน่นอนที่ฉันกำลังมองหาด้วยStringEnumConverterคุณสมบัติ:

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

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

รายละเอียดเพิ่มเติมที่มีอยู่ในเอกสารStringEnumConverter

มีสถานที่อื่น ๆ ในการกำหนดค่าตัวแปลงนี้ทั่วโลกมากขึ้น

  • enum เองถ้าคุณต้องการ enum เป็นอนุกรม / deserialized เป็นสตริงเสมอ:

    [JsonConverter(typeof(StringEnumConverter))]  
    enum Gender { Male, Female }
  • ในกรณีที่ทุกคนต้องการหลีกเลี่ยงการตกแต่งคุณลักษณะคุณสามารถเพิ่มตัวแปลงลงใน JsonSerializer ของคุณ (แนะนำโดยBjørn Egil ):

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

    และจะใช้ได้กับทุก enum ที่เห็นระหว่างการทำให้เป็นอนุกรม (แนะนำโดยTravis )

  • หรือ JsonConverter (แนะนำโดยกล้วย ):

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

นอกจากนี้คุณยังสามารถควบคุมปลอกและไม่ว่าตัวเลขที่ได้รับการยอมรับโดยยังคงใช้StringEnumConverter (NamingStrategy บูลีน)คอนสตรัค


9
ตามลิงค์เพื่อดูคำอธิบายวิธีการใช้งานใน asp.net mvc application james.newtonking.com/archive/2008/10/16/ …
RredCat

2
นี่คือลิงค์ไปยังฟังก์ชั่นนั้น: james.newtonking.com/projects/json/help/html/…
CAD bloke

61
HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; config.Formatters.JsonFormatter.SerializerSettings.Converters.Add (ใหม่ Newtonsoft.Json.Converters.StringEnumConverter ());
อิกกี

1
มันจะมีประโยชน์ที่จะทราบโดยค่าเริ่มต้น ASP.NET MVC ไม่ได้ใช้ Json.Net เป็น json serializer และหนึ่งต้องขยายControllerหรือแทนที่ด้วยตนเองทุกอนุกรม
Odys

2
คุณสามารถปรับแต่งตัวแปลง (พูดสำหรับcamelCaseเอาต์พุต):new StringEnumConverter { CamelCaseText = true }
Seafish

172

เพิ่มด้านล่างเพื่อ global.asax ของคุณสำหรับอนุกรม JSON ของ c # enum เป็นสตริง

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

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

4
ด้วยเหตุผลบางอย่างฉันไม่ได้รับสิ่งนี้ให้ทำงาน พู้ทำเล่นแสดง 2 ปากแข็งมากกว่า 'คำเตือน' แม้จะมีสิ่งนี้อยู่ นอกจากนี้ยังมี - เหตุผลว่าทำไมจะเปลี่ยนFormattingไปIndented?
sq33G

5
บรรทัดที่สามจากตัวอย่างนี้ถูกเพิ่มลงในไฟล์ App_start / webapiconfig.cs และทำเคล็ดลับสำหรับฉันในโครงการ ASP.NET Web API 2.1 เพื่อส่งคืนสตริงสำหรับค่า enum ในการเรียกใช้ REST (json fomat)
Greg Z.

1
มีวิธีการตั้งค่าคุณสมบัตินี้ตามขอบเขตการร้องขอเท่านั้นหรือไม่
Anestis Kivranoglou

@AnestisKivranoglou เพียงแค่ใช้ json serializer ที่กำหนดเองตามคำขอด้วยการตั้งค่าของตัวเอง
BrainSlugs83

3
การตั้งค่า serializer แรกของการเยื้องไม่เกี่ยวข้องกับคำถาม op
user3791372

153

@Iggy คำตอบตั้ง JSON เป็นอันดับ c # enum เป็นสตริงเฉพาะสำหรับ ASP.NET (Web API และอื่น ๆ )

แต่เพื่อให้สามารถทำงานร่วมกับซีเรียลไลซ์ ad hoc ได้ให้เพิ่มการติดตามคลาสเริ่มต้นของคุณ (เช่น 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;
});

ข้อมูลเพิ่มเติมเกี่ยวกับหน้า Json.NET

นอกจากนี้หากต้องการให้สมาชิก enum ของคุณเป็นลำดับ / ดีซีเรียลไลซ์ถึง / จากข้อความที่ระบุให้ใช้

System.Runtime.Serialization.EnumMember

คุณลักษณะเช่นนี้:

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

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

6
ขอบคุณ! [EnumMember]ผมก็แค่มองหา
Poulad

CamelCaseTextคุณสมบัติถูกทำเครื่องหมายขณะนี้ล้าสมัย วิธีใหม่ในการยกตัวอย่างแปลง:new StringEnumConverter(new CamelCaseNamingStrategy())
fiat

ขอบคุณมากทำวันของฉัน! :)
Eldoïr

39

ฉันไม่สามารถเปลี่ยนรูปแบบของแหล่งข้อมูลได้เหมือนในคำตอบยอดนิยม (ของ @ob.) และฉันไม่ต้องการลงทะเบียนทั่วโลกเช่น @Iggy ดังนั้นฉันจึงรวมhttps://stackoverflow.com/a/2870420/237091และ @ Iggy https://stackoverflow.com/a/18152942/237091เพื่ออนุญาตให้ตั้งค่าตัวแปลง enum สตริงระหว่างคำสั่ง 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()
        }
    })

woks นี้ยังดีถ้าคุณมีคุณสมบัติเช่นนี้รายการ <someEnumType>
Bogdan

34

การรวมกันของคำตอบของ Omer Bokhari และ uri นั้นเป็นวิธีการแก้ปัญหาของฉันเนื่องจากค่าที่ฉันต้องการให้มักแตกต่างจากสิ่งที่ฉันมีใน enum ของฉันโดยเฉพาะอย่างยิ่งที่ฉันต้องการจะเปลี่ยน enums ของฉันถ้าฉันต้องการ

ดังนั้นหากใครสนใจก็เป็นดังนี้:

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

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

1
ฉันใช้JsonPropertyAttributeสำหรับสมาชิก enum และมันใช้งานได้ง่าย น่าเศร้าในระหว่างการปรับแต่งด้วยตนเองกับJTokenมันจะได้รับการละเว้น Happilly EnumMemberAttributeทำงานเหมือนจับใจ ขอบคุณ!
Prolog

ใช้งานได้กับJavaScriptSerializer?
Stephen Kennedy

31

นี้จะกระทำได้อย่างง่ายดายโดยการเพิ่มScriptIgnoreแอตทริบิวต์กับGenderคุณสมบัติที่ทำให้มันไม่ต่อเนื่องและการเพิ่มGenderStringคุณสมบัติที่ไม่ได้รับการต่อเนื่อง:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

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

29
ให้ฉันพยายามอธิบาย โซลูชันนี้ไม่ถูกต้องตาม paters ออกแบบ คุณแก้ไขโมเดลตามวัตถุประสงค์ในการดู แต่รุ่นจะต้องมีข้อมูลเท่านั้นและไม่สนใจงานนำเสนอ คุณต้องย้ายฟังก์ชั่นนี้ในเลเยอร์อื่น
RredCat

4
ที่จริงแล้ว Model นั้นใช้ในการส่งผ่านข้อมูลจากคอนโทรลเลอร์และเป็นคอนโทรลเลอร์ซึ่งไม่สนใจงานนำเสนอ บทนำของคุณสมบัติอัตโนมัติ (ออฟไลน์ที่นี่) ไม่ทำลายคอนโทรลเลอร์ซึ่งยังคงใช้คุณสมบัติเพศ แต่ให้การเข้าถึงที่ง่ายสำหรับมุมมอง วิธีแก้ปัญหาเชิงตรรกะ
Dima

17
@RredCat ไม่มีอะไรผิดปกติกับการมีคุณสมบัติเฉพาะมุมมองใน "มุมมองรูปแบบ" IMHO ข้อผิดพลาดจะไม่แยกโมเดลมุมมองออกจากโมเดลโดเมน: blogs.msdn.com/b/simonince/archive/2010/01/26/…
Mariano Desanze

5
@RredCat แม้ว่ามันจะไม่ถูกต้องตามรูปแบบบางส่วน OP ไม่ได้พูดอะไรเกี่ยวกับเรื่องนี้ดังนั้นนี่จึงเป็นคำตอบที่ถูกต้อง (แม้ว่าฉันปรัชญาอาจเห็นด้วยกับจุดของคุณ.)
MEMark

10
การปั่นจักรยานที่ไร้สาระอย่างบ้าคลั่งในหัวข้อความคิดเห็นนี้เป็นสิ่งที่น่าสนใจ
Mike Mooney

26

คำตอบของ Stephen รุ่นนี้จะไม่เปลี่ยนชื่อใน 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; 
        }
    }
}

3
ฉันเชื่อว่านี่ถูกต้องสำหรับDataContractJsonSerializerไม่JavaScriptSerializer
KCD

ง่ายและแก้ปัญหาให้ฉันโดยใช้ serializers Framework .NET ดั้งเดิม
สมาชิกวุฒิสภา

ทางออกที่ดีที่สุดสำหรับฉันเนื่องจากฉันไม่ได้รับอนุญาตให้ใช้ห้องสมุดของบุคคลที่สาม (ปัญหาความ
สอดคล้องกับ

นี่ไม่ใช่สำหรับประเภทของซีเรียลไลเซอร์ในคำถามที่แน่นอน JavaScriptSerializer ทำให้ทุกอย่างที่ไม่ได้ถูกทำเป็นซีเรียลต่อเนื่องในขณะที่ DataContractJsonSerializer นั้นต้องการคุณลักษณะ DataMember ขอบคุณที่ตะโกนออกมา แต่โปรดทราบว่าคุณสะกดชื่อฉันผิด :)
สตีเฟ่นเคนเนดี

25

นี่คือคำตอบสำหรับ newtonsoft.json

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

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

1
ขอบคุณสำหรับคำตอบนี้ช่วยฉันได้มาก! หากคุณต้องการกำหนด enums ของคุณใน PascalCase แต่คุณต้องการให้มันเป็นอนุกรมใน camelCase แล้วคุณต้องเพิ่มtrueประเภท JsonConverter ของคุณเช่นนี้:[JsonConverter(typeof(StringEnumConverter), true)]
Peet


16

คุณสามารถเพิ่มตัวแปลงให้กับคุณได้JsonSerializerหากคุณไม่ต้องการใช้แอJsonConverterททริบิวต์:

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

มันจะทำงานได้กับทุกenumสิ่งที่เห็นในระหว่างการทำให้เป็นอนุกรม


15

นี่เป็นวิธีแก้ปัญหาอย่างง่ายที่ทำให้ซี # enum เป็นเซิร์ฟเวอร์กับ JSON และใช้ผลลัพธ์เพื่อเติม<select>องค์ประกอบของฝั่งไคลเอ็นต์ ใช้งานได้กับทั้ง enums อย่างง่ายและ bitflag enums

ฉันได้รวมวิธีการแก้ปัญหาแบบครบวงจรเพราะฉันคิดว่าคนส่วนใหญ่ต้องการเรียงลำดับ C # enum ให้กับ JSON ก็อาจจะใช้วิธีนี้เพื่อเติมรายการ<select>แบบหล่นลง

ไปที่นี่:

ตัวอย่าง Enum

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

enum ที่ซับซ้อนที่ใช้ OR ค่าบิตเพื่อสร้างระบบการอนุญาต ดังนั้นคุณไม่สามารถพึ่งพาดัชนีอย่างง่าย [0,1,2 .. ] สำหรับค่าจำนวนเต็มของ enum

ฝั่งเซิร์ฟเวอร์ - 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);
};

รหัสข้างต้นใช้เฟรมเวิร์ก NancyFX เพื่อจัดการกับคำขอรับ มันใช้Response.AsJson()วิธีการช่วยเหลือของ Nancy แต่ไม่ต้องกังวลคุณสามารถใช้ฟอร์แมต JSON มาตรฐานใด ๆ เนื่องจาก enum ได้รับการฉายในรูปแบบที่ไม่ระบุชื่อแบบง่ายพร้อมสำหรับการทำให้เป็นอนุกรม

สร้าง JSON

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

ฝั่งไคลเอ็นต์ - 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 ก่อนหน้า

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

HTML หลังจาก

<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

สำหรับแกน ASP.Net เพียงเพิ่มสิ่งต่อไปนี้ในคลาสเริ่มต้นของคุณ:

JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });

1
สิ่งนี้ใช้ได้กับทุกเวอร์ชั่นไม่ใช่เฉพาะคอร์
bikeman868

11

คุณสามารถสร้าง JsonSerializerSettings ด้วยการโทรไปที่ JsonConverter.SerializeObject ดังนี้:

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

10

สังเกตว่าไม่มีคำตอบสำหรับการทำให้เป็นอนุกรมเมื่อมีแอตทริบิวต์คำอธิบาย

นี่คือการใช้งานของฉันที่รองรับคุณสมบัติคำอธิบาย

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
}

การใช้งาน:

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

10

สำหรับ. Net Core: -

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

2
หากนี่คือหนึ่งจากที่Microsoft.AspNetCore.Mvc.Formatters.Jsonแพคเกจ NuGet ดูเหมือนว่าจะเป็นเพียงวิธีขยายบนไม่IMvcCoreBuilder ดังนั้นจึงใช้เช่นIMvcBuilder services.AddMvcCore().AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
infl3x

9

ใน. net core 3 สามารถทำได้โดยใช้คลาสที่มีอยู่แล้วใน System.Text.Json:

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

ในการกำหนดค่าJsonStringEnumConverterด้วยการตกแต่งคุณสมบัติสำหรับคุณสมบัติเฉพาะ:

using System.Text.Json.Serialization;

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

หากคุณต้องการแปลง enum เป็นสตริงเสมอให้ใส่แอตทริบิวต์ที่ enum เอง

[JsonConverter(typeof(JsonStringEnumConverter))] 
enum Gender { Male, Female }

9

Asp.Net Core 3 พร้อม System.Text.Json

public void ConfigureServices(IServiceCollection services)
{

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

    //...
 }

8

ในกรณีที่มีคนพบว่าไม่เพียงพอฉันจบลงด้วยการโอเวอร์โหลดนี้:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())

นี่เป็นทางออกที่ดีสำหรับกรณีการใช้งานของฉันในปัจจุบัน: ฉันไม่ต้องการเปลี่ยนค่าเริ่มต้นของ serializers และฉันมีปัญหาในการใช้คุณสมบัติเนื่องจากคุณสมบัติของฉันเป็นประเภท IList <EnumType>
Dirk Brockhaus

5

นี่เป็นคำถามเก่า แต่ฉันคิดว่าฉันจะมีส่วนร่วมในกรณี ในโครงการของฉันฉันใช้รุ่นแยกต่างหากสำหรับคำขอ Json ใด ๆ โดยทั่วไปโมเดลจะมีชื่อเหมือนกับวัตถุโดเมนที่มีคำนำหน้า "Json" รุ่นถูกแมปโดยใช้AutoMapper โดยการมีรูปแบบ json ประกาศคุณสมบัติสตริงที่เป็น enum ในระดับโดเมน AutoMapper จะแก้ไขให้เป็นงานนำเสนอสตริง

ในกรณีที่คุณสงสัยฉันต้องการรุ่นแยกต่างหากสำหรับคลาสที่ต่อเนื่องกันของ Json เนื่องจากตัวเรียงลำดับแบบ inbuilt เกิดขึ้นพร้อมกับการอ้างอิงแบบวงกลม

หวังว่านี่จะช่วยใครซักคน


ยินดีที่ได้เรียนรู้คุณลักษณะของ Automapper ;-) แอตทริบิวต์ [ScriptIgnore] จะลบการอ้างอิงแบบวงกลม
ledragon

1
โอ้ ไม่ทราบเกี่ยวกับคุณลักษณะ ขอบคุณ! คุณจะใช้สิ่งนั้นกับ Pocos ของคุณหรือไม่? ฉันใช้วิธีการนิยาม MetadataType สำหรับคุณลักษณะ Poco ใด ๆ เพื่อรักษาความสะอาด แอตทริบิวต์นี้จะยังทำงานผ่านข้อมูลเมตาได้หรือไม่
Ales Potocnik Hahonina

3

คุณสามารถใช้ JavaScriptConverter เพื่อทำสิ่งนี้ด้วย JavaScriptSerializer ในตัว โดยการแปลง enum ของคุณเป็น Uri คุณสามารถเข้ารหัสเป็นสตริงได้

ฉันได้อธิบายวิธีการทำเช่นนี้สำหรับวันที่ แต่สามารถใช้สำหรับ enums ได้เช่นกัน รูปแบบที่กำหนดเอง DateTime JSON สำหรับ NET JavaScriptSerializer


ทางออกที่น่าสนใจมาก! ขอบคุณสำหรับการแบ่งปัน.
โอลิเวอร์

1

ไม่แน่ใจว่านี่ยังเกี่ยวข้องอยู่หรือไม่ แต่ฉันต้องเขียนตรงไปยังไฟล์ json และฉันได้คำตอบต่อไปนี้พร้อมกันหลายคำตอบ

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

มันรับรองคีย์ json ทั้งหมดของฉันเป็นตัวพิมพ์เล็กเริ่มต้นตาม "กฎ" json จัดรูปแบบมันเยื้องอย่างหมดจดและละเว้น nulls ในเอาต์พุต นอกจากนี้ด้วยการเพิ่ม StringEnumConverter มันพิมพ์ enums ด้วยค่าสตริงของพวกเขา

โดยส่วนตัวแล้วฉันคิดว่านี่เป็นสิ่งที่สะอาดที่สุดที่ฉันสามารถทำได้โดยไม่ต้องทำให้โมเดลสกปรกด้วยคำอธิบายประกอบ

การใช้งาน:

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

0

ฉันได้รวบรวมทุกส่วนของโซลูชันนี้โดยใช้Newtonsoft.Jsonห้องสมุด จะแก้ไขปัญหา enum และทำให้ข้อผิดพลาดในการจัดการดีขึ้นมากและทำงานใน IIS บริการโฮสต์ มันเป็นโค้ดจำนวนมากดังนั้นคุณสามารถค้นหาได้บน GitHub ที่นี่: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

คุณต้องเพิ่มรายการบางรายการของคุณWeb.configเพื่อให้สามารถใช้งานได้คุณสามารถดูไฟล์ตัวอย่างได้ที่นี่: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config


0

และสำหรับ VB.net ฉันพบงานต่อไปนี้:

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)

0

ตัวเลือกการพิสูจน์ในอนาคตเพิ่มเติมเล็กน้อย

เมื่อเผชิญกับคำถามเดียวกันเราได้พิจารณาแล้วว่าเราต้องการรุ่นที่กำหนดเองStringEnumConverterเพื่อให้แน่ใจว่าค่า enum ของเราสามารถขยายตัวได้ตลอดเวลาโดยไม่ทำให้เกิดความหายนะทางด้าน deserializing (ดูพื้นหลังด้านล่าง) การใช้SafeEnumConverterด้านล่างอนุญาตให้การดีซีเรียลไลเซชันให้เสร็จสมบูรณ์แม้ว่าเพย์โหลดจะมีค่าสำหรับ enum ที่ไม่มีคำจำกัดความที่กำหนดชื่อให้ใกล้เคียงกับการแปลง int-to-enum

การใช้งาน:

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

หรือ

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

ที่มา:

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

พื้นหลัง

เมื่อเราดูที่การใช้StringEnumConverterปัญหาที่เรามีก็คือเรายังต้องการความเงียบสำหรับกรณีที่มีการเพิ่มค่า enum ใหม่ แต่ลูกค้าทุกคนไม่ได้ตระหนักถึงคุณค่าใหม่ทันที ในกรณีเหล่านี้StringEnumConverterแพ็กเกจที่มี Newtonsoft JSON JsonSerializationExceptionจะคล้ายกับ "ข้อผิดพลาดในการแปลงค่า SomeString ให้พิมพ์ EnumType" และกระบวนการ deserialization ทั้งหมดล้มเหลว นี่เป็นตัวจัดการข้อตกลงสำหรับเราเพราะแม้ว่าลูกค้าวางแผนที่จะเพิกเฉย / ทิ้งมูลค่าทรัพย์สินที่ไม่เข้าใจ แต่ก็ยังต้องมีความสามารถในการแยกแยะส่วนที่เหลือของส่วนที่เหลือ!


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

-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]  
);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.