Обеспечение того, чтобы ключи json были строчными в .NET

103

Есть ли простой способ использовать JSON в .NET, чтобы гарантировать, что ключи отправляются в нижнем регистре?

На данный момент я использую библиотеку newtonsoft Json.NET и просто использую

string loginRequest = JsonConvert.SerializeObject(auth);

В данном случае authэто как раз следующий объект

public class Authority
{
    public string Username { get; set; }
    public string ApiToken { get; set; }
}

Это приводит к

{"Username":"Mark","ApiToken":"xyzABC1234"}

Есть ли способ , чтобы гарантировать , что usernameи apitokenключи поставляются через в нижнем регистре?

Я, конечно, не хочу просто прогонять его, String.ToLower()потому что значения для usernameи apitokenимеют смешанный регистр.

Я понимаю, что могу сделать это программно и создать строку JSON вручную, но мне это нужно примерно для 20 или около того строк данных JSON, и я смотрю, смогу ли я сэкономить время. Мне интересно, есть ли какие-нибудь уже созданные библиотеки, которые позволяют применять строчные буквы для создания ключей.

отметка
источник
Может быть, библиотека сериализации json предлагает какие-то атрибуты сериализации, которые вы могли бы использовать для изменения сериализованных имен json ваших свойств?
tdammers 09
@tdammers, спасибо, я пытаюсь найти что-то, что делает это, но пока безуспешно. Надеюсь, кто-то здесь может указать мне на это.
Марк
1
Это может быть полезно, если ваш текст состоит из одного слова.
Lipotam
Ага. У меня противоположная проблема ... также - забавно, что вы упоминаете "Имя пользователя" в смешанном регистре. Вы имели в виду "UserName"?
BrainSlugs83
Нет, просто значения должны оставаться смешанными, если только клавиши были тем, к чему мне нужно было прикоснуться. Ценность оставьте в покое.
Марк

Ответы:

176

Для этого вы можете создать собственный преобразователь контрактов. Следующий преобразователь контрактов преобразует все ключи в нижний регистр:

public class LowercaseContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        return propertyName.ToLower();
    }
}

Использование:

var settings = new JsonSerializerSettings();
settings.ContractResolver = new LowercaseContractResolver();
var json = JsonConvert.SerializeObject(authority, Formatting.Indented, settings);

Результатом будет:

{"username":"Mark","apitoken":"xyzABC1234"}

Если вы всегда хотите сериализовать с помощью LowercaseContractResolver, подумайте о том, чтобы обернуть его в класс, чтобы не повторяться:

public class LowercaseJsonSerializer
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new LowercaseContractResolver()
    };

    public static string SerializeObject(object o)
    {
        return JsonConvert.SerializeObject(o, Formatting.Indented, Settings);
    }

    public class LowercaseContractResolver : DefaultContractResolver
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            return propertyName.ToLower();
        }
    }
}

Что можно использовать так:

var json = LowercaseJsonSerializer.SerializeObject(new { Foo = "bar" });
// { "foo": "bar" }

ASP.NET MVC4 / WebAPI

Если вы используете ASP.NET MVC4 / WebAPI, вы можете использовать CamelCasePropertyNamesContractResolverбиблиотеку Newtonsoft.Json, которая включена по умолчанию.

Алексей
источник
какой-нибудь разумный способ сделать это наоборот? Для десериализации?
Шон Роуэн,
1
@Anzeo Я не пробовал делать это сам и не нашел информации об этом в документации. Решением было бы обернуть JsonConvert.SerializeObject в свой собственный класс. Смотрите мое обновление.
Alexn
3
Похоже, этот настраиваемый преобразователь контрактов не учитывает атрибут JsonProperty, если вы хотите указать исключения ... например, [JsonProperty ("alternateName")] по-прежнему отображается в нижнем регистре или есть другой способ сделать это?
rekna
2
+1 за указание на CamelCasePropertyNamesContractResolver. Я обнаружил, System.Net.Http.Formatting.JsonContractResolverчто это значение по умолчанию в WebAPI, и этот класс является внутренним. Я заканчиваю перезапись JsonContractResolverс помощью верблюжьего корпуса. Кто-то сообщил, что это общедоступно aspnetwebstack.codeplex.com/workitem/228
CallMeLaNN
10
CamelCasePropertyNamesContratResolverне преобразовывайте свойства в нижний регистр, только первый символ.
ToXinE
23
protected void Application_Start() {
    JsonConfig.Configure();   
}

public static class JsonConfig
{
    public static void Configure(){
        var formatters = GlobalConfiguration.Configuration.Formatters;
        var jsonFormatter = formatters.JsonFormatter;
        var settings = jsonFormatter.SerializerSettings;

        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}
Саги
источник
10

В Json.NET 9.0.1 и более поздних версиях можно обеспечить преобразование имен всех свойств в нижний регистр с помощью пользовательского NamingStrategy. Этот класс извлекает логику для алгоритмического переназначения имен свойств из преобразователя контракта в отдельный легкий объект, который может быть установлен DefaultContractResolver.NamingStrategy. Это избавляет от необходимости создавать пользовательские настройкиContractResolver и, таким образом, может быть проще интегрировать в структуры, у которых уже есть свои собственные преобразователи контрактов.

Определите LowercaseNamingStrategyследующее:

public class LowercaseNamingStrategy : NamingStrategy
{
    protected override string ResolvePropertyName(string name)
    {
        return name.ToLowerInvariant();
    }
}

Затем выполните сериализацию следующим образом:

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver { NamingStrategy = new LowercaseNamingStrategy() },
};
string loginRequest = JsonConvert.SerializeObject(auth, settings);

Ноты -

  • Использование string.ToLowerInvariant()гарантирует, что один и тот же контракт будет создан во всех регионах.

  • Для того, чтобы контролировать ли строчные имена переопределены собственности, ключи словаря и имена данных расширения, вы можете установить NamingStrategy.OverrideSpecifiedNames, NamingStrategy.ProcessDictionaryKeysили NamingStrategy.ProcessExtensionDataNames(Json.NET 10.0.1 и позже) к true.

  • Вы можете захотеть кэшировать преобразователь контрактов для лучшей производительности .

  • Если у вас нет доступа к настройкам сериализатора в вашей платформе, вы можете применить NamingStrategyнепосредственно к своему объекту следующим образом:

    [JsonObject(NamingStrategyType = typeof(LowercaseNamingStrategy))]
    public class Authority
    {
        public string Username { get; set; }
        public string ApiToken { get; set; }
    }
  • Не изменяйте NamingStrategyоф CamelCasePropertyNamesContractResolver. Этот преобразователь контрактов совместно использует информацию о типах во всех своих экземплярах, поэтому изменение любого одного экземпляра может иметь неожиданные побочные эффекты.

dbc
источник
8

вы можете использовать "JsonProperty":

Использование:

public class Authority
{
    [JsonProperty("userName")] // or [JsonProperty("username")]
    public string Username { get; set; }
    [JsonProperty("apiToken")] // or [JsonProperty("apitoken")]
    public string ApiToken { get; set; }
}

var json  = JsonConvert.SerializeObject(authority);
Йоргелиг
источник
0

Для меня я использовал комбинацию некоторых других ответов и в итоге получил это

        return JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        });

был ближе к решению того, что я искал, поскольку я не стремился создавать свой собственный

рабочий байт
источник