Переконайтеся, що клавіші json мають малі літери в .NET


103

Чи є простий спосіб за допомогою JSON у .NET переконатися, що ключі надсилаються як малі регістри?

На даний момент я використовую бібліотеку Json.NET Newtonsoft і просто користуюся

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, і я бачу, чи можу я заощадити час. Мені цікаво, чи є вже побудовані бібліотеки, які дозволяють застосувати малі регістри для створення ключів.


Можливо, lib серіалізація json пропонує якісь атрибути серіалізації, які ви могли використовувати для зміни назв серіалізованих json ваших властивостей?
тдаммери

@tdammers, дякую, я намагаюся знайти щось, що це робить, але поки що не вдалося. Сподіваючись, що хтось тут міг би вказати мені на це.
Марк

1
Це може бути корисно у випадку, якщо ваша власність складається з одного слова.
Ліпотам

Ага. У мене є протилежна проблема ... також - смішно, що ви згадуєте "Ім'я користувача" - це змішаний випадок. Ви мали на увазі "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, яка включена за замовчуванням.


будь-який розумний спосіб зробити це в зворотному порядку? Для десеріалізації?
Shaun Rowan

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. Цей укладач договору ділиться інформацією у всьому світі у всіх своїх випадках, і тому зміна будь-якого одного екземпляра може мати несподівані побічні ефекти.


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()
        });

був ближче до вирішення того, що я шукав, оскільки не шукав створити свою власну

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.