c# - newtonsoft - stringenumconverter
.NET-JSON-сериализация перечисления как строки (14)
@Iggy отвечает на JSON-сериализацию c # enum как строки только для 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;
});
Дополнительная информация на странице Json.NET
Кроме того, чтобы ваш член перечисления выполнял сериализацию / десериализацию в / из определенного текста, используйте
System.Runtime.Serialization.EnumMember
атрибут, например:
public enum time_zone_enum
{
[EnumMember(Value = "Europe/London")]
EuropeLondon,
[EnumMember(Value = "US/Alaska")]
USAlaska
}
У меня есть класс, который содержит свойство enum
, и после сериализации объекта с помощью JavaScriptSerializer
мой результат json содержит целочисленное значение перечисления, а не его string
«name». Есть ли способ получить перечисление в виде string
в моем json, не создавая собственный JavaScriptConverter
? Возможно, есть атрибут, который я мог бы украсить определением enum
или свойством объекта?
В качестве примера:
enum Gender { Male, Female }
class Person
{
int Age { get; set; }
Gender Gender { get; set; }
}
Желаемый результат json:
{ "Age": 35, "Gender": "Male" }
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
Вот простое решение, которое сериализует перечисление C # на стороне сервера для JSON и использует результат для заполнения элемента <select>
стороне клиента. Это работает как для простых перечислений, так и для битфлаговых перечислений.
Я включил комплексное решение, потому что я думаю, что большинство людей, желающих сериализовать перечисление C # на JSON, также, вероятно, будут использовать его для заполнения раскрывающегося списка <select>
.
Вот оно:
Пример перечисления
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 #
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's Response.AsJson()
- но не беспокойтесь, вы можете использовать любой стандартный форматировщик 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>
Вы можете создать JsonSerializerSettings с вызовом JsonConverter.SerializeObject, как показано ниже:
var result = JsonConvert.SerializeObject
(
dataObject,
new JsonSerializerSettings
{
Converters = new [] {new StringEnumConverter()}
}
);
Для .Net Core Web Api: -
public void ConfigureServices(IServiceCollection services)
{
...
services.AddJsonFormatters(f => f.Converters.Add(new StringEnumConverter()));
...
}
Для ядра ASP.Net Просто добавьте следующее в свой класс запуска:
JsonConvert.DefaultSettings = (() =>
{
var settings = new JsonSerializerSettings();
settings.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
return settings;
});
Заметил, что нет ответа на сериализацию при наличии атрибута 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");
}
}
Enum:
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; }
Комбинация ответов Омера Бокхари и ури - это мое решение, так как ценности, которые я хочу предоставить, обычно отличаются от того, что у меня есть в моем перечислении специально, что я хотел бы иметь возможность изменять свои перечисления, если мне нужно.
Поэтому, если кто-то заинтересован, это что-то вроде этого:
public enum Gender
{
[EnumMember(Value = "male")]
Male,
[EnumMember(Value = "female")]
Female
}
class Person
{
int Age { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
Gender Gender { get; set; }
}
Нет никакого специального атрибута, который вы можете использовать. JavaScriptSerializer
сериализует enums
в свои числовые значения, а не их строковое представление. Вам нужно будет использовать пользовательскую сериализацию для сериализации enum
как своего имени вместо числового значения.
Изменить: Как отметил @OmerBakhari, JSON.net охватывает этот прецедент (через атрибут [JsonConverter(typeof(StringEnumConverter))]
) и многие другие, которые не обрабатываются встроенными сериализаторами .net. Вот ссылка, сравнивающая функции и функциональные возможности сериализаторов .
Фактически вы можете использовать JavaScriptConverter для выполнения этого со встроенным JavaScriptSerializer. Преобразуя enum в Uri, вы можете закодировать его как строку.
Я описал, как это сделать для дат, но также можно использовать для перечислений.
http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/
Это легко сделать, добавив атрибут ScriptIgnore
в свойство Gender
, в результате чего он не будет сериализован и GenderString
свойство GenderString
которое сериализуется:
class Person
{
int Age { get; set; }
[ScriptIgnore]
Gender Gender { get; set; }
string GenderString { get { return Gender.ToString(); } }
}
Это старый вопрос, но я думал, что буду способствовать на всякий случай. В моих проектах я использую отдельные модели для любых запросов Json. Модель обычно имеет то же имя, что и объект домена с префиксом «Json». Модели отображаются с помощью AutoMapper . Благодаря тому, что модель json объявляет свойство string, которое является перечислением в классе домена, AutoMapper будет разрешать его представление строки.
В случае, если вам интересно, мне нужны отдельные модели для сериализованных классов Json, потому что встроенный сериализатор в свою очередь предлагает круговые ссылки.
Надеюсь, это поможет кому-то.
Я обнаружил, что Json.NET обеспечивает точную функциональность, которую я ищу с атрибутом StringEnumConverter
:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
[JsonConverter(typeof(StringEnumConverter))]
public Gender Gender { get; set; }
Более подробная информация доступна в документации StringEnumConverter
.
Я собрал все части этого решения, используя библиотеку Newtonsoft.Json
. Он исправляет проблему перечисления, а также делает обработку ошибок намного лучше, и она работает в службах IIS. Это довольно много кода, поэтому вы можете найти его на GitHub здесь: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs
Вы должны добавить некоторые записи в свой Web.config
чтобы заставить его работать, вы можете увидеть пример файла здесь: https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config