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

Ome*_*ari 1088 c# asp.net enums json javascriptserializer

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

举个例子:

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }
    Gender Gender { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

期望的json结果:

{ "Age": 35, "Gender": "Male" }
Run Code Online (Sandbox Code Playgroud)

Ome*_*ari 1999

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

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

[JsonConverter(typeof(StringEnumConverter))]
public Gender Gender { get; set; }
Run Code Online (Sandbox Code Playgroud)

有关StringEnumConverter文档的更多详细信息.

  • HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; config.Formatters.JsonFormatter.SerializerSettings.Converters.Add (new Newtonsoft.Json.Converters.StringEnumConverter()); (56认同)
  • 按照链接描述如何在asp.net mvc应用程序中使用它http://james.newtonking.com/archive/2008/10/16/asp-net-mvc-and-json-net.aspx (9认同)
  • 以下是该功能的链接:http://james.newtonking.com/projects/json/help/html/T_Newtonsoft_Json_Converters_StringEnumConverter.htm (2认同)
  • 你可以自定义转换器(例如,对于`camelCase`输出):`new StringEnumConverter {CamelCaseText = true}` (2认同)

Mat*_*ing 341

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

编辑: 正如@OmerBakhari所指出的那样,JSON.net涵盖了这个用例(通过属性JavaScriptSerializer)以及许多其他内部.net序列化程序无法处理的用例.这是一个比较序列化器的特性和功能的链接.

  • 请将此删除作为已接受的答案,因为它无法解决问题,下面的答案是1000+ upvotes DOES. (40认同)
  • @ BrainSlugs83 - 问题是关于使用JavaScriptSerializer,而不是Json.NET(如果你看一下修订历史,你会看到有一个编辑来澄清),如果你使用JavaScriptSerializer属性`JsonConverter`不会工作. (12认同)
  • @Fabzter - 你的解决方案使用了Newtonsoft的Json (6认同)

Igg*_*ggy 168

将以下内容添加到您的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());
Run Code Online (Sandbox Code Playgroud)

  • 此示例的第三行已添加到App_start/webapiconfig.cs文件中,并在ASP.NET Web API 2.1项目中为我做了一个技巧,以返回REST(json fomat)调用中枚举值的字符串. (5认同)
  • 出于某种原因,我没有让这个工作.Fiddler显示出顽固的2而不是'警告',即使有这个.另外 - 为什么要将`Formatting`改为`Indented`的任何理由? (4认同)
  • 缩进的第一个序列化程序设置与op问题无关。 (2认同)

Jur*_*uri 146

@Iggy的答案将c#enum的JSON序列化设置为仅用于ASP.NET的字符串(Web 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;
});
Run Code Online (Sandbox Code Playgroud)

有关Json.NET页面的更多信息

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

System.Runtime.Serialization.EnumMember

属性,像这样:

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

    [EnumMember(Value = "US/Alaska")] 
    USAlaska
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!我只是在寻找`[EnumMember]`。 (4认同)

Sco*_*ord 39

我无法像最终答案(@ob.)那样更改源模型,我不想像@Iggy那样全局注册.所以我结合/sf/answers/200929431/和@ Iggy的/sf/answers/1270705971/,允许在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()
        }
    })
Run Code Online (Sandbox Code Playgroud)


Ash*_*ous 32

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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 我将“JsonPropertyAttribute”用于枚举成员,它适用于简单的反序列化任务。遗憾的是,在使用“JToken”进行手动调整期间,它被忽略了。令人高兴的是,“EnumMemberAttribute”就像一个魅力。谢谢! (2认同)

Ste*_*edy 31

这是很容易通过添加完成ScriptIgnore属性的Gender属性,使其不被序列化,并增加了GenderString其性能确实得到连载:

class Person
{
    int Age { get; set; }

    [ScriptIgnore]
    Gender Gender { get; set; }

    string GenderString { get { return Gender.ToString(); } }
}
Run Code Online (Sandbox Code Playgroud)

  • 让我试着解释一下.根据设计专家的说法,此解决方案不正确.您根据视图目的修改了模型.但模型必须仅包含数据,而不关心演示文稿.您必须在另一层上移动此功能. (28认同)
  • @RredCat在"视图模型"中具有特定于视图的属性没有任何问题.恕我直言,错误不是将视图模型从域模型中分离出来:http://blogs.msdn.com/b/simonince/archive/2010/01/26/view-models-in-asp-net-mvc. ASPX (17认同)
  • 在这个评论帖中迂回荒谬的自行车脱落令人着迷. (9认同)
  • @RredCat,即使根据某种模式不正确,OP也没有说明这一点,所以这确实是一个正确的答案.(即使我在哲学上可能同意你的观点.) (5认同)
  • 实际上,Model用于从控制器传递数据,ant是控制器,不关心表示.自动化属性(GenderString here)的引入不会破坏控制器,它仍然使用Gender属性,但提供了对视图的轻松访问.逻辑解决方案. (4认同)
  • @ user3285954这是使用内置JavaScriptSerializer实现所需序列化的一种廉价方法,即它可以回答问题。只有字符串会被序列化,所以我真的看不到问题。如果您要优雅,请使用Json.Net;如果您需要快速解决所出现的问题,并希望通过内置序列化程序使用asmx或页面方法,则可以找到答案。 (2认同)

mhe*_*man 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; 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我相信这对于`DataContractJsonSerializer`而不是`JavaScriptSerializer`是有效的 (3认同)

小智 25

这是newtonsoft.json的答案

enum Gender { Male, Female }

class Person
{
    int Age { get; set; }

    [JsonConverter(typeof(StringEnumConverter))]
    Gender Gender { get; set; }
}
Run Code Online (Sandbox Code Playgroud)


O. *_*hai 23

对于.NET 6.0如果您想使用内置JsonSerializer(System.Text.Json)

然后,它是开箱即用的,您只需要使用内置JsonStringEnumConverter属性即可。例如:

[JsonConverter(typeof(JsonStringEnumConverter))]
public SomeEnumType EnumProperty { get; set; }
Run Code Online (Sandbox Code Playgroud)

就是这样,但请确保您SomeEnumType包含的值具有确切的字符串值,否则它将引发异常。外壳似乎不敏感。

参考: https: //learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-customize-properties ?pivots=dotnet-6-0#enums-as-strings


st1*_*st1 22

ASP.NET核心方式:

public class Startup
{
  public IServiceProvider ConfigureServices(IServiceCollection services)
  {
    services.AddMvc().AddJsonOptions(options =>
    {
      options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

https://gist.github.com/regisdiogo/27f62ef83a804668eb0d9d0f63989e3e


Ser*_*-Tm 22

带有 System.Text.Json 的 Asp.Net Core 3

public void ConfigureServices(IServiceCollection services)
{

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

    //...
 }
Run Code Online (Sandbox Code Playgroud)


bio*_*tal 15

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

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

开始:

示例枚举

public enum Role
{
    None = Permission.None,
    Guest = Permission.Browse,
    Reader = Permission.Browse| Permission.Help ,
    Manager = Permission.Browse | Permission.Help | Permission.Customise
}
Run Code Online (Sandbox Code Playgroud)

一个复杂的枚举,它使用按位OR来生成权限系统.所以你不能依赖简单的索引[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);
};
Run Code Online (Sandbox Code Playgroud)

上面的代码使用NancyFX框架来处理Get请求.它使用Nancy的Response.AsJson()辅助方法 - 但不要担心,您可以使用任何标准JSON格式化程序,因为枚举已经被投射到一个简单的匿名类型,可以进行序列化.

生成的JSON

[
    {"Id":0,"Name":"None"},
    {"Id":2097155,"Name":"Guest"},
    {"Id":2916367,"Name":"Reader"},
    {"Id":4186095,"Name":"Manager"}
]
Run Code Online (Sandbox Code Playgroud)

客户端 - 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
Run Code Online (Sandbox Code Playgroud)

HTML之前

<select id="role" name="role"></select>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)


Jer*_*yal 15

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

string SerializedResponse = JsonConvert.SerializeObject(
     objToSerialize, 
     new Newtonsoft.Json.Converters.StringEnumConverter()
); 
Run Code Online (Sandbox Code Playgroud)

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


Yah*_*ein 13

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

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


Yan*_*ang 11

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

var result = JsonConvert.SerializeObject
            (
                dataObject,
                new JsonSerializerSettings
                {
                    Converters = new [] {new StringEnumConverter()}
                }
            );
Run Code Online (Sandbox Code Playgroud)


Gre*_*lor 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

枚举:

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

    // Will be serialized as "Applicable"
    Applicable
}
Run Code Online (Sandbox Code Playgroud)

用法:

[JsonConverter(typeof(CustomStringEnumConverter))]
public FooEnum test { get; set; }
Run Code Online (Sandbox Code Playgroud)


Pet*_*eGO 10

对于.Net Core Web Api: -

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 如果这是来自Microsoft.AspNetCore.Mvc.Formatters.Json NuGet包中的方法,则它似乎只是IMvcCoreBuilder上的扩展方法,而不是IMvcBuilder上的扩展方法。因此它的用法类似于`services.AddMvcCore()。AddJsonFormatters(f =&gt; f.Converters.Add(new StringEnumConverter()));`。 (2认同)

小智 10

用这个:

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

[Serializable]
[JsonConverter(typeof(StringEnumConverter))]
public enum Gender { Male, Female }
Run Code Online (Sandbox Code Playgroud)


Ale*_*ina 5

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

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

希望这有助于某人.


hng*_*r18 5

以防万一有人发现上述不足,我最终解决了这个过载:

JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
Run Code Online (Sandbox Code Playgroud)


Bjö*_*örn 5

在.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);
Run Code Online (Sandbox Code Playgroud)

JsonStringEnumConverter特定属性配置属性装饰:

using System.Text.Json.Serialization;

[JsonConverter(typeof(JsonStringEnumConverter))]
public Gender Gender { get; set; }
Run Code Online (Sandbox Code Playgroud)

如果要始终将枚举转换为字符串,请将属性放在枚举本身。

[JsonConverter(typeof(JsonStringEnumConverter))] 
enum Gender { Male, Female }
Run Code Online (Sandbox Code Playgroud)

  • 漂亮又干净。 (4认同)