Mam projekt Web Api konfigurowany w następujący sposób:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Jednak chcę, aby wielkość liter w klawiszach słownika pozostała niezmieniona. czy jest jakiś atrybut, Newtonsoft.Json
którego mogę użyć do klasy, aby wskazać, że chcę, aby wielkość liter pozostała niezmieniona podczas serializacji?
public class SomeViewModel
{
public Dictionary<string, string> Data { get; set; }
}
Odpowiedzi:
Nie ma atrybutu, który mógłby to zrobić, ale możesz to zrobić, dostosowując program rozpoznawania nazw.
Widzę, że już używasz
CamelCasePropertyNamesContractResolver
. Jeśli wyprowadzisz z tego nową klasę przelicznika i przesłoniszCreateDictionaryContract()
metodę, możesz zapewnić funkcję zastępcząDictionaryKeyResolver
, która nie zmienia nazw kluczy.Oto kod, którego potrzebujesz:
class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver { protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) { JsonDictionaryContract contract = base.CreateDictionaryContract(objectType); contract.DictionaryKeyResolver = propertyName => propertyName; return contract; } }
Próbny:
class Program { static void Main(string[] args) { Foo foo = new Foo { AnIntegerProperty = 42, HTMLString = "<html></html>", Dictionary = new Dictionary<string, string> { { "WHIZbang", "1" }, { "FOO", "2" }, { "Bar", "3" }, } }; JsonSerializerSettings settings = new JsonSerializerSettings { ContractResolver = new CamelCaseExceptDictionaryKeysResolver(), Formatting = Formatting.Indented }; string json = JsonConvert.SerializeObject(foo, settings); Console.WriteLine(json); } } class Foo { public int AnIntegerProperty { get; set; } public string HTMLString { get; set; } public Dictionary<string, string> Dictionary { get; set; } }
Oto wynik z powyższego. Zwróć uwagę, że wszystkie nazwy właściwości klas mają wielkość liter wielbłąda, ale klucze słownika zachowały swoją oryginalną wielkość liter.
{ "anIntegerProperty": 42, "htmlString": "<html></html>", "dictionary": { "WHIZbang": "1", "FOO": "2", "Bar": "3" } }
źródło
contract.DictionaryKeyResolver = key => key;
działa dobrze.DictionaryKeyResolver
tylko wtedy, gdy moja właściwość Dictionary ma jakiś niestandardowy atrybut?Json.NET 9.0.1 wprowadził
NamingStrategy
hierarchię klas do obsługi tego rodzaju problemów. Wyodrębnia logikę algorytmicznego ponownego mapowania nazw właściwości z mechanizmu rozpoznawania kontraktu do oddzielnej, lekkiej klasy, która umożliwia kontrolę nad tym, czy klucze słownika , jawnie określone nazwy właściwości i nazwy danych rozszerzeń (w wersji 10.0.1 ) są ponownie mapowane.Używając
DefaultContractResolver
i ustawiającNamingStrategy
na wystąpienieCamelCaseNamingStrategy
you, możesz wygenerować JSON z nazwami właściwości w postaci wielbłądów i niezmodyfikowanymi kluczami słownika, ustawiając je wJsonSerializerSettings.ContractResolver
:var resolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = false, OverrideSpecifiedNames = true } }; config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = resolver;
Uwagi:
Bieżąca implementacja
CamelCasePropertyNamesContractResolver
określa również, że członkowie .Net z wyraźnie określonymi nazwami właściwości (np. Te , dla którychJsonPropertyAttribute.PropertyName
zostały ustawione) powinny mieć przemapowane nazwy:public CamelCasePropertyNamesContractResolver() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; }
Powyższe
resolver
zachowuje to zachowanie. Jeśli tego nie chcesz, ustawOverrideSpecifiedNames = false
.Json.NET ma kilka wbudowanych strategii nazewnictwa, w tym:
CamelCaseNamingStrategy
. Strategia nazewnictwa przypadków wielbłądów, która zawiera logikę przemapowywania nazw wcześniej osadzoną wCamelCasePropertyNamesContractResolver
.SnakeCaseNamingStrategy
. Przypadek wąż strategia nazewnictwa.DefaultNamingStrategy
. Domyślna strategia nazewnictwa. Nazwy właściwości i klucze słownika pozostają niezmienione.Możesz też utworzyć własną, dziedzicząc po abstrakcyjnej klasie bazowej
NamingStrategy
.Chociaż można również zmodyfikować
NamingStrategy
wystąpienie programuCamelCasePropertyNamesContractResolver
, ponieważ ten ostatni udostępnia informacje o kontrakcie globalnie we wszystkich wystąpieniach każdego typu , może to prowadzić do nieoczekiwanych skutków ubocznych, jeśli aplikacja spróbuje użyć wielu wystąpieńCamelCasePropertyNamesContractResolver
. Nie ma takiego problemuDefaultContractResolver
, więc bezpieczniej jest używać go, gdy wymagane jest jakiekolwiek dostosowanie logiki obudowy.źródło
public Dictionary<string, Dictionary<string, string>> Values { get; set; }
. Nadal robi camelCase dla kluczy słownika wewnętrznego.CamelCasePropertyNamesContractResolver
. ZasadniczoNamingStrategy
pierwszy wpływ miałby na kontrakty generowane przez drugi. To może być to, co widzisz. Zamiast tego wypróbuj nowe zalecenie i daj mi znać, jeśli rozwiąże problem.NamingStrategy
, aby był w stanie przeanalizować zarówno skrzynkę wielbłąda, jak i skrzynkę pascalową?config
powinno być w początkowym przykładzie kodu ?config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
. Wygląda na internetowy interfejs API MVC 4HttpConfiguration
, zobacz Jak ustawić niestandardowe JsonSerializerSettings dla Json.NET w MVC 4 Web API? .To bardzo miła odpowiedź. Ale dlaczego po prostu nie zastąpić
ResolveDictionaryKey
?class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver { #region Overrides of DefaultContractResolver protected override string ResolveDictionaryKey(string dictionaryKey) { return dictionaryKey; } #endregion }
źródło
Wybrana odpowiedź jest idealna, ale myślę, że w momencie, gdy to piszę, narzędzie do rozpoznawania kontraktu musi zmienić się na coś takiego, ponieważ DictionaryKeyResolver już nie istnieje :)
public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver { protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) { JsonDictionaryContract contract = base.CreateDictionaryContract(objectType); contract.PropertyNameResolver = propertyName => propertyName; return contract; } }
źródło
DictionaryKeyResolver
został dodany w wersji 7.0.1 iPropertyNameResolver
został oznaczony jako przestarzały.