首页 文章

.NET - 枚举的jSON序列化为字符串

提问于
浏览
928

我有一个包含 enum 属性的类,在使用 JavaScriptSerializer 序列化对象时,我的json结果包含枚举的整数值而不是 string "name" . 有没有办法在我的json中将枚举作为 string 而无需创建自定义 JavaScriptConverter ?也许有一个属性我可以装饰 enum 定义或对象属性?

举个例子:

enum Gender { Male, Female }

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

期望的json结果:

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

21 回答

  • 31
    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]  
    );
    
  • 26

    我不想像@Iggy那样全球注册 . 因此,我将https://stackoverflow.com/a/2870420/237091和@ Iggy的https://stackoverflow.com/a/18152942/237091组合在一起,以允许在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()
            }
        })
    
  • 10

    注意到存在Description属性时没有序列化的答案 .

    这是我的实现,它支持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; }
    
  • 114

    这是一个简单的解决方案,它将服务器端C#枚举序列化为JSON,并使用结果填充客户端 <select> 元素 . 这适用于简单的枚举和bitflag枚举 .

    我已经包含了端到端解决方案,因为我认为大多数人想要将C#枚举序列化为JSON也可能会使用它来填充 <select> 下拉列表 .

    开始:

    Example Enum

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

    一个复杂的枚举,它使用按位OR来生成权限系统 . 因此,您不能依赖简单索引[0,1,2 ..]作为枚举的整数值 .

    Server Side - 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() 辅助方法 - 但不要担心,您可以使用任何标准JSON格式化程序,因为枚举已经被投射到一个简单的匿名类型中,可以进行序列化 .

    Generated JSON

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

    Client Side - 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 Before

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

    HTML After

    <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>
    
  • 0

    将以下内容添加到您的global.asax中,以便将c#enum的JSON序列化作为字符串

    HttpConfiguration config = GlobalConfiguration.Configuration;
                config.Formatters.JsonFormatter.SerializerSettings.Formatting =
                    Newtonsoft.Json.Formatting.Indented;
    
                config.Formatters.JsonFormatter.SerializerSettings.Converters.Add
                    (new Newtonsoft.Json.Converters.StringEnumConverter());
    
  • 11

    对于.Net Core Web Api: -

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

    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

  • 1750

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

    如果您想知道,我需要Json序列化类的单独模型,因为内置序列化器会提供循环引用 .

    希望这有助于某人 .

  • 5

    这可以通过向 Gender 属性添加ScriptIgnore属性,导致它不被序列化,并添加一个被序列化的 GenderString 属性来轻松完成:

    class Person
    {
        int Age { get; set; }
    
        [ScriptIgnore]
        Gender Gender { get; set; }
    
        string GenderString { get { return Gender.ToString(); } }
    }
    
  • 249

    如果您不想使用 JsonConverter 属性,还可以向 JsonSerializer 添加转换器:

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

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

  • 11

    Omer Bokhari和uri的答案的结合是我的解决方案,因为我想提供的 Value 通常与我在枚举中的 Value 不同,特别是如果我需要,我希望能够更改我的枚举 .

    所以,如果有人有兴趣,它是这样的:

    public enum Gender
    {
       [EnumMember(Value = "male")] 
       Male,
       [EnumMember(Value = "female")] 
       Female
    }
    
    class Person
    {
        int Age { get; set; }
        [JsonConverter(typeof(StringEnumConverter))]
        Gender Gender { get; set; }
    }
    
  • 4

    对于ASP.Net核心只需将以下内容添加到您的启动类:

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

    这是newtonsoft.json的答案

    enum Gender { Male, Female }
    
    class Person
    {
        int Age { get; set; }
    
        [JsonConverter(typeof(StringEnumConverter))]
        Gender Gender { get; set; }
    }
    
  • 7

    您可以使用内置的JavaScriptSerializer实际使用JavaScriptConverter来实现此目的 . 通过将枚举转换为Uri,您可以将其编码为字符串 .

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

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

  • 22

    我使用 Newtonsoft.Json 库汇总了此解决方案的所有部分 . 它修复了枚举问题并使错误处理更好,并且可以在IIS托管服务中使用 . 这是很多代码,所以你可以在GitHub上找到它:https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs

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

  • 4

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

    Edit: 正如@OmerBakhari所指出的那样,JSON.net涵盖了这个用例(通过属性 [JsonConverter(typeof(StringEnumConverter))] )以及许多其他内部.net序列化程序无法处理的用例 . Here is a link comparing features and functionalities of the serializers .

  • -4

    为了防止任何人发现上述不足,我最终解决了这个过载问题:

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

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

    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;
    
    [JsonConverter(typeof(StringEnumConverter))]
    public Gender Gender { get; set; }
    

    更多详情请见StringEnumConverter documentation .

  • 3

    @Iggy的答案将c#enum的JSON序列化设置为仅用于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;
    });
    

    更多信息on the Json.NET page

    此外,要让您的枚举成员序列化/反序列化为特定文本,请使用

    System.Runtime.Serialization.EnumMember

    属性,像这样:

    public enum time_zone_enum
    {
        [EnumMember(Value = "Europe/London")] 
        EuropeLondon,
    
        [EnumMember(Value = "US/Alaska")] 
        USAlaska
    }
    
  • 13

    此版本的Stephen的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; 
            }
        }
    }
    
  • 9

    您可以通过调用JsonConverter.SerializeObject来创建JsonSerializerSettings,如下所示:

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

相关问题