关于C#:.NET – 枚举的jSON序列化为字符串

.NET - JSON serialization of enum as string

我有一个包含enum属性的类,在使用JavaScriptSerializer序列化对象时,我的json结果包含枚举的整数值,而不是它的string名称。有没有一种方法可以在我的JSON中获得作为string的枚举,而不必创建自定义JavaScriptConverter?也许有一个属性可以用来修饰enum定义或对象属性?

举个例子:

1
2
3
4
5
6
7
enum Gender { Male, Female }

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

期望的JSON结果:

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


我发现json.net提供了我正在寻找的具有StringEnumConverter属性的确切功能:

1
2
3
4
5
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

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

更多详细信息,请参阅StringEnumConverter文档。


不,没有可以使用的特殊属性。JavaScriptSerializerenums序列化为其数值,而不是其字符串表示形式。您需要使用自定义序列化来序列化enum作为其名称,而不是数字值。

编辑:正如@omerbakhari json.net所指出的那样,它涵盖了这个用例(通过属性[JsonConverter(typeof(StringEnumConverter))])和许多其他内置.NET序列化程序无法处理的用例。下面是一个链接,比较序列化程序的特性和功能。


Add the below to your global.asax for JSON serialization of c# enum as string

1
2
3
4
5
6
  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 answer将C枚举的JSON序列化设置为仅用于ASP.NET(Web API等)的字符串。

但是为了使它也能与特殊的序列化一起工作,请将以下内容添加到您的start类中(如global.asax application_start)

1
2
3
4
5
6
7
//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

属性,如下所示:

1
2
3
4
5
6
7
8
public enum time_zone_enum
{
    [EnumMember(Value ="Europe/London")]
    EuropeLondon,

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


我无法像在顶级答案中那样更改源模型(在@ob中),而且我不想像@igy那样在全球范围内注册它。因此,我结合了https://stackoverflow.com/a/2870420/237091和@iggy的https://stackoverflow.com/a/18152942/237091,以允许在序列化对象命令本身期间设置字符串枚举转换器:

1
2
3
4
5
6
7
8
9
Newtonsoft.Json.JsonConvert.SerializeObject(
    objectToSerialize,
    Newtonsoft.Json.Formatting.None,
    new Newtonsoft.Json.JsonSerializerSettings()
    {
        Converters = new List<Newtonsoft.Json.JsonConverter> {
            new Newtonsoft.Json.Converters.StringEnumConverter()
        }
    })


这很容易通过向Gender属性添加ScriptIgnore属性,使其不序列化,并添加一个GenderString属性来实现:

1
2
3
4
5
6
7
8
9
class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

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


此版本的斯蒂芬回答不会更改JSON中的名称:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[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;
        }
    }
}


OmerBokhari和Uri的答案的组合也是我的解决方案,因为我想要提供的值通常不同于我的枚举中的值,特别是如果需要的话,我希望能够更改我的枚举。

所以如果有人感兴趣的话,应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum Gender
{
   [EnumMember(Value ="male")]
   Male,
   [EnumMember(Value ="female")]
   Female
}

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


这是newtonsoft.json的答案。

1
2
3
4
5
6
7
8
9
enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

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


ASP.NET核心方式:

1
2
3
4
5
6
7
8
9
10
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


这里有一个简单的解决方案,它将服务器端的C枚举序列化为JSON,并使用结果填充客户端的下拉列表。

下面是:

实例枚举

1
2
3
4
5
6
7
public enum Role
{
    None = Permission.None,
    Guest = Permission.Browse,
    Reader = Permission.Browse| Permission.Help ,
    Manager = Permission.Browse | Permission.Help | Permission.Customise
}

使用按位ORS生成权限系统的复杂枚举。因此,不能依赖简单索引[0,1,2..]来获取枚举的整数值。

服务器端-C#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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()helper方法——但不用担心,您可以使用任何标准的JSON格式化程序,因为枚举已经被投影到一个简单的匿名类型中,可以进行序列化。

生成的JSON

1
2
3
4
5
6
[
    {"Id":0,"Name":"None
<hr><P>如果不想使用<wyn>JsonConverter</wyn>属性,还可以向<wyn>JsonSerializer</wyn>添加转换器:</P>[cc lang="
csharp"]string SerializedResponse = JsonConvert.SerializeObject(
     objToSerialize,
     new Newtonsoft.Json.Converters.StringEnumConverter()
);

它将适用于它在序列化过程中看到的每个enum


可以通过调用jsonConverter.SerializeObject创建jsonSerializerSettings,如下所示:

1
2
3
4
5
6
7
8
var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );

对于.NET核心Web API:

1
2
3
4
5
6
public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}


对于ASP.NET核心,只需在启动类中添加以下内容:

1
2
3
4
5
6
JsonConvert.DefaultSettings = (() =>
        {
            var settings = new JsonSerializerSettings();
            settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
            return settings;
        });

注意,当存在description属性时,没有对序列化的应答。

这是我的实现,它支持描述属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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");
    }
}

枚举:

1
2
3
4
5
6
7
8
9
public enum FooEnum
{
    // Will be serialized as"Not Applicable"
    [Description("Not Applicable")]
    NotApplicable,

    // Will be serialized as"Applicable"
    Applicable
}

用途:

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

这是一个古老的问题,但我认为我会做出贡献以防万一。在我的项目中,我对任何JSON请求使用单独的模型。模型通常与带有"json"前缀的域对象同名。使用automapper映射模型。通过让JSON模型声明一个字符串属性,该属性是域类上的枚举,automapper将解析为它的字符串表示。

如果您想知道,我需要为JSON序列化类使用单独的模型,因为内置序列化程序会遇到循环引用。

希望这能帮助别人。


为了防止有人发现上述不足,我最终解决了这个负担:

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

实际上,可以使用javascriptconverter通过内置的javascriptserializer来实现这一点。通过将枚举转换为URI,可以将其编码为字符串。

我已经描述了如何对日期执行此操作,但它也可以用于枚举。

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


不确定这是否仍然相关,但我必须直接写到一个JSON文件中,然后我将下面几个stackoverflow答案拼凑在一起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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"规则"开始。将其格式设置为完全缩进,并忽略输出中的空值。aslo通过添加一个StringEnumConverter,它可以打印带有字符串值的枚举。

就我个人而言,我觉得这是我能想到的最干净的方法,不必用注释弄脏模型。

用途:

1
2
3
4
5
6
7
8
    internal void SaveJson(string fileName)
    {
        // serialize JSON directly to a file
        using (StreamWriter file = File.CreateText(@fileName))
        {
            LowercaseJsonSerializer.Serialize(file, jsonobject);
        }
    }

我已经使用Newtonsoft.Json库把这个解决方案的所有部分放在一起。它修复了枚举问题,并且使错误处理变得更好,并且它可以在IIS托管服务中工作。它有很多代码,所以你可以在Github上找到它:https://github.com/jongrant/wcfjsonserializer/blob/master/newtonsoftjsonformatter.cs

您必须在Web.config中添加一些条目才能使其正常工作,您可以在这里看到一个示例文件:https://github.com/jongrant/wcfjsonserializer/blob/master/web.config


1
2
3
4
5
6
7
8
9
10
11
12
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]  
);