Сериализация .NET - JSON перечисления как строки
у меня есть класс, который содержит элемент enum
свойства, и при сериализации объекта с помощью JavaScriptSerializer
мой результат 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" }
20 ответов
нет нет специального атрибута, который вы можете использовать. JavaScriptSerializer
сериализует enums
к их числовым значениям, а не к их строковому представлению. Вам нужно будет использовать пользовательскую сериализацию для сериализации enum
как его имя вместо числового значения.
Edit:
Как отметил @OmerBakhari JSON.net охватывает этот вариант использования (через атрибут [JsonConverter(typeof(StringEnumConverter))]
) и многие другие не обрабатываются встроенными сериализаторами .net. вот ссылка сравнения характеристик и функции сериализаторы.
я обнаружил, что Json.NET обеспечивает точное функциональность, я ищу с :
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
[JsonConverter(typeof(StringEnumConverter))]
public Gender Gender { get; set; }
более подробная информация доступна на StringEnumConverter
документация.
добавьте ниже к глобальному.asax для сериализации JSON перечисления c# как string
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 устанавливает сериализацию JSON перечисления c# как строку только для ASP.NET (Web API и так далее).
но чтобы он работал также с специальной сериализацией, добавьте следующее в свой класс start (например, Global.событий 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 страница
кроме того, чтобы иметь член перечисления для сериализации/десериализации в/из определенного текста, используйте
, например:public enum time_zone_enum { [EnumMember(Value = "Europe/London")] EuropeLondon, [EnumMember(Value = "US/Alaska")] USAlaska }
Я не смог изменить исходную модель, как в верхнем ответе (@ob.), и я не хотел регистрировать его глобально, как @Iggy. Поэтому я объединил https://stackoverflow.com/a/2870420/237091 и @Iggy's 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()
}
})
это легко сделать, добавив ScriptIgnore
до Gender
свойство, в результате чего оно не будет сериализовано и добавлено GenderString
имущества,тут сделать по частям:
class Person
{
int Age { get; set; }
[ScriptIgnore]
Gender Gender { get; set; }
string GenderString { get { return Gender.ToString(); } }
}
эта версия Стивена ответ не изменяет имя в 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;
}
}
}
вот ответ для newtonsoft.в JSON
enum Gender { Male, Female }
class Person
{
int Age { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
Gender Gender { get; set; }
}
вот простое решение, которое сериализует серверное перечисление 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
}
A сложное перечисление, использующее побитовые ORs для создания системы разрешений. Поэтому вы не можете полагаться на простой индекс [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. Он использует вспомогательный метод-но не волнуйтесь, вы можете использовать любой стандартный форматер 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>
комбинация ответов Омера Бухари и Ури также является моим решением, поскольку значения, которые я хочу предоставить, обычно отличаются от того, что у меня есть в моем перечислении, особенно, что я хотел бы иметь возможность изменить мои перечисления, если мне нужно.
поэтому, если кто-то заинтересован, это что-то вроде этого:
public enum Gender
{
[EnumMember(Value = "male")]
Male,
[EnumMember(Value = "female")]
Female
}
class Person
{
int Age { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
Gender Gender { get; set; }
}
вы можете создать JsonSerializerSettings с вызовом JsonConverter.SerializeObject, как показано ниже:
var result = JsonConvert.SerializeObject
(
dataObject,
new JsonSerializerSettings
{
Converters = new [] {new StringEnumConverter()}
}
);
вы также можете добавить конвертер в свой JsonSerializer
Если вы не хотите использовать :
string SerializedResponse = JsonConvert.SerializeObject(
objToSerialize,
new Newtonsoft.Json.Converters.StringEnumConverter()
);
это будет работать для каждого enum
он видит во время этой сериализации.
Для .Net Core Web Api : -
public void ConfigureServices(IServiceCollection services)
{
...
services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
...
}
заметил, что нет ответа для сериализации, когда есть атрибут 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; }
Это старый вопрос, но я думал, что внесу свой вклад на всякий случай. В моих проектах я использую отдельные модели для любых запросов Json. Модель обычно имеет то же имя, что и объект домена с префиксом "Json". Модели сопоставляются с помощью AutoMapper. Если модель json объявит строковое свойство, которое является перечислением в классе домена, AutoMapper разрешит его строковое представление.
Если вам интересно, мне нужны отдельные модели для сериализованных классов Json потому что встроенный сериализатор придумывает циклические ссылки в противном случае.
надеюсь, это кому-то поможет.
вы можете фактически использовать JavaScriptConverter для выполнения этого со встроенным JavaScriptSerializer. Преобразуя перечисление в Uri, вы можете кодировать его как строку.
Я описал, как это сделать для дат, но его можно использовать и для перечислений.
http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/
на всякий случай, если кто-нибудь сочтет вышеизложенное недостаточным, я в конечном итоге решил эту перегрузку:
JsonConvert.SerializeObject(objToSerialize, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())
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
Я собрал все части этого решения, используя Newtonsoft.Json
библиотека. Он устраняет проблему перечисления, а также делает обработку ошибок намного лучше, и он работает в службах IIS. Это довольно много кода, поэтому вы можете найти его на GitHub здесь: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs
вы должны добавить некоторые записи в вашем Web.config
чтобы заставить его работать, вы можете увидеть пример файла здесь:
https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config
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]
);