it-swarm-ko.tech

열거 형의 JSON 직렬화

enum 속성이 포함 된 클래스가 있고 JavaScriptSerializer 사용하여 개체를 serialize 할 때 내 json 결과 string "이름"대신 열거 형 정수 값이 들어 있습니다. 사용자 정의 string을 만들 필요없이 내 json에서 JavaScriptConverter으로 열거 형을 가져올 수있는 방법이 있습니까? 아마도 enum 정의 나 객체 속성을 꾸밀 수있는 속성이 있습니까?

예로서:

enum Gender { Male, Female }

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

원하는 json 결과 :

{ "Age": 35, "Gender": "Male" }
992
Omer Bokhari

아니오 특별한 속성을 사용할 수 없습니다. JavaScriptSerializer은 문자열 표현이 아닌 숫자 값으로 enums을 직렬화합니다. 사용자 지정 직렬화를 사용하여 enum을 숫자 값 대신 이름으로 직렬화해야합니다.

Edit : @OmerBakhari에 의해 지적 된대로 JSON.net은 ([JsonConverter(typeof(StringEnumConverter))] 속성을 통해)이 유스 케이스와 내장 된 .net 시리얼 라이저에 의해 처리되지 않는 많은 것들을 다룹니다. 여기에는 시리얼 라이저의 기능과 기능을 비교하는 링크가 있습니다 .

298
Matt Dearing

나는 Json.NETStringEnumConverter 속성으로 찾고있는 정확한 기능을 제공합니다.

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

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

자세한 내용은 StringEnumConverter documentation 에서 참조하십시오.

1862
Omer Bokhari

문자열을 C # enum으로 JSON 직렬화를 위해 global.asax에 아래 코드를 추가하십시오.

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

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

@이지 답변은 C # # enum의 JSON 직렬화를 ASP.NET (웹 API 등)의 문자열로만 설정합니다.

하지만 임시 직렬화에서도 작동하게하려면 시작 클래스에 다음을 추가하십시오 (예 : 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 페이지에서

또한 특정 텍스트로 직렬화/역 직렬화하도록 열거 형 멤버를 지정하려면

System.Runtime.Serialization.EnumMember

다음과 같은 속성 :

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

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

최상위 응답 (@ob.)과 같은 소스 모델을 변경할 수 없었고 @Iggy처럼 전역으로 등록하고 싶지 않았습니다. 그래서 나는 https://stackoverflow.com/a/2870420/237091 와 @ Iggy 's 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()
        }
    })
34
Scott Stafford

이것은 ScriptIgnore 속성에 Gender 속성을 추가하여 직렬화되지 않도록하고 does serialize되는 GenderString 속성을 추가하여 쉽게 수행 할 수 있습니다.

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

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

Omer Bokhari와 uri의 조합은 내가 제공하고자하는 값이 대개 내 열거 형과 다른 경우이므로 필자의 열거 형을 변경할 수 있기를 바란다.

누군가가 관심을 가지면 다음과 같이됩니다.

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

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

이 버전의 Stephen 's answer 는 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
mheyman

Newtonsoft.json에 대한 답변입니다.

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

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

ASP.NET 핵심 방법 :

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

15
st1

다음은 서버 측 C # enum을 JSON으로 serialize하고 결과를 사용하여 클라이언트 측 <select> 요소를 채우는 간단한 솔루션입니다. 이는 간단한 enum과 bitflag enum 모두에 적용됩니다.

JSON으로 C # 열거 형을 serialize하려는 대부분의 사람들이 <select> 드롭 다운을 채우기 위해이 열거 형을 사용하고있을 것이라고 생각하기 때문에이 종단 간 솔루션을 포함 시켰습니다.

여기에 간다 :

예제 Enum

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

비트 OR을 사용하여 사용 권한 시스템을 생성하는 복잡한 enum입니다. 그래서 열거 형의 정수 값에 대해 간단한 인덱스 [0,1,2 ..]에 의존 할 수 없습니다.

서버 측 - 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 프레임 워크를 사용하여 Get 요청을 처리합니다. Nancy의 Response.AsJson() 도우미 메서드를 사용하지만 enum이 이미 직렬화 준비가되어있는 단순한 익명 형식으로 투영되었으므로 표준 JSON 형식화기를 사용할 수 있으므로 걱정하지 않아도됩니다.

생성 된 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>
14
biofractal

JsonSerializer 특성을 사용하지 않으려면 JsonConverter에 변환기를 추가 할 수도 있습니다.

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

직렬화 중에 보이는 모든 enum에 대해 작동합니다.

13
JerryGoyal

아래와 같이 JsonConverter.SerializeObject를 호출하여 JsonSerializerSettings를 만들 수 있습니다.

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

.Net 핵심 웹 API의 경우 : -

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

ASP.Net 코어의 경우 시작 클래스에 다음을 추가하십시오.

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

Description 특성이있는 경우 serialization에 대한 응답이 없음을 알 수 있습니다.

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

열거 형 :

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; }
7
Greg R Taylor

이것은 낡은 질문이지만, 만약에 대비해 기여할 것이라고 생각했습니다. 내 프로젝트에서는 모든 Json 요청에 대해 별도의 모델을 사용합니다. 모델은 일반적으로 "Json"접두사가있는 도메인 객체와 이름이 같습니다. 모델은 AutoMapper 를 사용하여 매핑됩니다. json 모델에서 도메인 클래스의 열거 형인 문자열 속성을 선언하도록하면 AutoMapper가 문자열 프리젠 테이션으로 변환됩니다.

당신이 궁금해하는 경우에, inbuilt 시리얼 라이저가 순환 참조를 제공하기 때문에 Json 직렬화 클래스에 대한 별도의 모델이 필요합니다.

희망이 사람을 도움이됩니다.

5

아무도 위의 내용이 충분하지 않을 경우를 대비하여이 과부하로 해결하게되었습니다.

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

실제로 JavaScriptConverter를 사용하여 내장 된 JavaScriptSerializer로이를 수행 할 수 있습니다. enum을 Uri로 변환하면 문자열로 인코딩 할 수 있습니다.

날짜에 대해 이렇게하는 방법을 설명했지만 enum에도 사용할 수 있습니다.

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

3
Sebastian Markbåge

이것이 아직 관련이 있는지 확실하지 않지만 json 파일에 직접 작성해야하며 다음과 같은 몇 가지 stackoverflow 답변을 함께 작성했습니다.

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 "규칙"에 따라 소문자로 시작한다는 것을 보장합니다. 형식이 깔끔하게 들여 쓰기되고 출력에서 ​​Null을 무시합니다. 또한 StringEnumConverter를 추가하여 문자열 값과 함께 열거 형을 인쇄합니다.

개인적으로이 모델은 주석을 사용하여 모델을 더러워 할 필요없이 가장 깨끗한 모델이라고 생각합니다.

용법:

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

그리고 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
Benjamin Swedlove

조금 더 미래 지향적 인 옵션

같은 질문에 직면하여, 역 직렬화 측면에서 치명적으로 파괴하지 않고 열거 형 값이 시간이 지남에 따라 확장 될 수 있도록 StringEnumConverter의 사용자 정의 버전이 필요하다고 판단했습니다 (아래 배경 참조). 아래의 SafeEnumConverter을 사용하면 페이로드에 명명 된 정의가없는 열거 형의 값이 포함되어있어 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 사용을 살펴봤을 때 문제는 새로운 열거 형 값이 추가 된 경우에도 수동성이 필요하지만 모든 클라이언트가 새로운 값을 즉시 인식 할 수는 없다는 것입니다. 이 경우 Newtonsoft JSON으로 패키지 된 StringEnumConverter은 "SomeString 값을 EnumType 유형으로 변환하는 중 오류 발생"과 유사한 JsonSerializationException을 발생시킨 다음 whole deserialization 프로세스가 실패합니다. 고객이 이해할 수없는 재산 가치를 무시/폐기 할 계획이 있었지만 여전히 나머지 페이로드를 역 직렬화 할 수 있어야했기 때문에 이것은 우리를위한 거래 차단기였습니다.

0
Dusty

나는이 솔루션의 모든 부분을 Newtonsoft.Json 라이브러리를 사용하여 작성했다. 열거 형 문제를 수정하고 오류 처리를 훨씬 향상시키고 IIS 호스팅 서비스에서 작동합니다. 꽤 많은 코드이므로 여기 GitHub에서 찾을 수 있습니다 : https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

작동 시키려면 Web.config에 몇 가지 항목을 추가해야합니다. 여기에 예제 파일이 있습니다. https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config

0
Jon Grant