J'ai un projet Web Api configuré comme ceci:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Cependant, je veux que le boîtier des clés du dictionnaire reste inchangé. y a-t-il un attribut que Newtonsoft.Json
je peux utiliser pour une classe pour indiquer que je veux que la casse reste inchangée pendant la sérialisation?
public class SomeViewModel
{
public Dictionary<string, string> Data { get; set; }
}
Réponses:
Il n'y a pas d'attribut pour faire cela, mais vous pouvez le faire en personnalisant le résolveur.
Je vois que vous utilisez déjà un fichier
CamelCasePropertyNamesContractResolver
. Si vous dérivez une nouvelle classe de résolveur à partir de cela et remplacez laCreateDictionaryContract()
méthode, vous pouvez fournir uneDictionaryKeyResolver
fonction de remplacement qui ne modifie pas les noms de clé.Voici le code dont vous auriez besoin:
class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver { protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) { JsonDictionaryContract contract = base.CreateDictionaryContract(objectType); contract.DictionaryKeyResolver = propertyName => propertyName; return contract; } }
Démo:
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; } }
Voici la sortie de ce qui précède. Notez que tous les noms de propriété de classe sont en camel, mais les clés du dictionnaire ont conservé leur casse d'origine.
{ "anIntegerProperty": 42, "htmlString": "<html></html>", "dictionary": { "WHIZbang": "1", "FOO": "2", "Bar": "3" } }
la source
contract.DictionaryKeyResolver = key => key;
fonctionne très bien.DictionaryKeyResolver
uniquement si ma propriété Dictionary possède un attribut personnalisé?Json.NET 9.0.1 a introduit la
NamingStrategy
hiérarchie des classes pour gérer ce type de problème. Il extrait la logique du remappage algorithmique des noms de propriété du résolveur de contrat vers une classe séparée et légère qui permet de contrôler si les clés de dictionnaire , les noms de propriété explicitement spécifiés et les noms de données d'extension (dans 10.0.1 ) sont remappés.En utilisant
DefaultContractResolver
et en définissantNamingStrategy
sur une instance de,CamelCaseNamingStrategy
vous pouvez générer du JSON avec des noms de propriété en cas de camel et des clés de dictionnaire non modifiées en le définissant dansJsonSerializerSettings.ContractResolver
:var resolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = false, OverrideSpecifiedNames = true } }; config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = resolver;
Remarques:
L'implémentation actuelle de
CamelCasePropertyNamesContractResolver
spécifie également que les membres .Net avec des noms de propriété explicitement spécifiés (par exemple ceux oùJsonPropertyAttribute.PropertyName
a été défini) doivent avoir leurs noms remappés:public CamelCasePropertyNamesContractResolver() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; }
Ce qui précède
resolver
préserve ce comportement. Si vous ne le souhaitez pas, réglezOverrideSpecifiedNames = false
.Json.NET a plusieurs stratégies de dénomination intégrées, notamment:
CamelCaseNamingStrategy
. Une stratégie de dénomination de cas de chameau qui contient la logique de remappage de nom précédemment intégrée dansCamelCasePropertyNamesContractResolver
.SnakeCaseNamingStrategy
. Une stratégie de dénomination de cas de serpent .DefaultNamingStrategy
. La stratégie de dénomination par défaut. Les noms de propriété et les clés de dictionnaire restent inchangés.Ou, vous pouvez créer le vôtre en héritant de la classe de base abstraite
NamingStrategy
.Bien qu'il soit également possible de modifier le
NamingStrategy
d'une instance deCamelCasePropertyNamesContractResolver
, étant donné que cette dernière partage les informations de contrat globalement sur toutes les instances de chaque type , cela peut entraîner des effets secondaires inattendus si votre application tente d'utiliser plusieurs instances deCamelCasePropertyNamesContractResolver
. Aucun problème de ce type n'existe avecDefaultContractResolver
, il est donc plus sûr à utiliser lorsqu'une personnalisation de la logique de boîtier est requise.la source
public Dictionary<string, Dictionary<string, string>> Values { get; set; }
. Il fait toujours camelCase pour les clés du dictionnaire interne.CamelCasePropertyNamesContractResolver
. Fondamentalement,NamingStrategy
le premier influencerait les contrats générés par le second. C'est peut- être ce que vous voyez. Essayez plutôt la nouvelle recommandation et faites-moi savoir si elle résout votre problème.NamingStrategy
, de sorte qu'il soit capable d'analyser à la fois l'étui camel et l'étui pascal?config
censé être?config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
. Il semble s'agir de l'API Web MVC 4HttpConfiguration
, consultez Comment définir des paramètres JsonSerializerSettings personnalisés pour Json.NET dans l'API Web MVC 4? .C'est une très belle réponse. Mais pourquoi ne pas simplement remplacer le
ResolveDictionaryKey
?class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver { #region Overrides of DefaultContractResolver protected override string ResolveDictionaryKey(string dictionaryKey) { return dictionaryKey; } #endregion }
la source
La réponse sélectionnée est parfaite mais je suppose qu'au moment où je tape ceci, le résolveur de contrat doit changer pour quelque chose comme ça parce que DictionaryKeyResolver n'existe plus :)
public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver { protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) { JsonDictionaryContract contract = base.CreateDictionaryContract(objectType); contract.PropertyNameResolver = propertyName => propertyName; return contract; } }
la source
DictionaryKeyResolver
a été ajouté dans la version 7.0.1 et aPropertyNameResolver
été marqué comme obsolète.