Tengo un proyecto de Web Api que se configura así:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Sin embargo, quiero que las mayúsculas y minúsculas del diccionario permanezcan sin cambios. ¿Hay algún atributo Newtonsoft.Json
que pueda usar en una clase para indicar que quiero que la carcasa permanezca sin cambios durante la serialización?
public class SomeViewModel
{
public Dictionary<string, string> Data { get; set; }
}
Respuestas:
No hay un atributo para hacer esto, pero puede hacerlo personalizando el resolutor.
Veo que ya estás usando un
CamelCasePropertyNamesContractResolver
. Si deriva una nueva clase de resolución de eso y anula elCreateDictionaryContract()
método, puede proporcionar unaDictionaryKeyResolver
función sustituta que no cambie los nombres de las claves.Aquí está el código que necesitaría:
class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver { protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) { JsonDictionaryContract contract = base.CreateDictionaryContract(objectType); contract.DictionaryKeyResolver = propertyName => propertyName; return contract; } }
Manifestación:
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; } }
Aquí está el resultado de lo anterior. Observe que todos los nombres de propiedad de la clase están en mayúsculas, pero las claves del diccionario han conservado su formato original.
{ "anIntegerProperty": 42, "htmlString": "<html></html>", "dictionary": { "WHIZbang": "1", "FOO": "2", "Bar": "3" } }
fuente
contract.DictionaryKeyResolver = key => key;
funciona bien.DictionaryKeyResolver
solo si mi propiedad de Diccionario tiene algún atributo personalizado?Json.NET 9.0.1 introdujo la
NamingStrategy
jerarquía de clases para manejar este tipo de problemas. Extrae la lógica para la reasignación algorítmica de los nombres de propiedad del solucionador de contratos a una clase ligera separada que permite controlar si las claves del diccionario , los nombres de propiedad especificados explícitamente y los nombres de datos de extensión (en 10.0.1 ) se reasignan.Al usar
DefaultContractResolver
y configurarNamingStrategy
una instancia deCamelCaseNamingStrategy
, puede generar JSON con nombres de propiedad en mayúsculas y minúsculas y claves de diccionario sin modificar configurándolo enJsonSerializerSettings.ContractResolver
:var resolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = false, OverrideSpecifiedNames = true } }; config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = resolver;
Notas:
La implementación actual de
CamelCasePropertyNamesContractResolver
también especifica que los miembros .Net con nombres de propiedad explícitamente especificados (por ejemplo, aquellos dondeJsonPropertyAttribute.PropertyName
se ha establecido) deben tener sus nombres reasignados:public CamelCasePropertyNamesContractResolver() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; }
Lo anterior
resolver
conserva este comportamiento. Si no quieres esto, configúraloOverrideSpecifiedNames = false
.Json.NET tiene varias estrategias de nomenclatura integradas que incluyen:
CamelCaseNamingStrategy
. Una estrategia de nomenclatura de casos de camello que contiene la lógica de reasignación de nombres que antes estaba incorporadaCamelCasePropertyNamesContractResolver
.SnakeCaseNamingStrategy
. Una estrategia de nomenclatura de casos de serpientes .DefaultNamingStrategy
. La estrategia de nomenclatura predeterminada. Los nombres de propiedad y las claves del diccionario no se modifican.O puede crear el suyo propio heredando de la clase base abstracta
NamingStrategy
.Si bien también es posible modificar el
NamingStrategy
de una instancia deCamelCasePropertyNamesContractResolver
, dado que este último comparte la información del contrato de forma global en todas las instancias de cada tipo , esto puede provocar efectos secundarios inesperados si su aplicación intenta usar varias instancias deCamelCasePropertyNamesContractResolver
. No existe tal problema conDefaultContractResolver
, por lo que es más seguro usarlo cuando se requiere cualquier personalización de la lógica de carcasa.fuente
public Dictionary<string, Dictionary<string, string>> Values { get; set; }
. Todavía hace camelCase para las claves internas del diccionario.CamelCasePropertyNamesContractResolver
. BásicamenteNamingStrategy
para el primero influiría en los contratos generados por el segundo. Eso podría ser lo que estás viendo. En su lugar, pruebe la nueva recomendación y avíseme si soluciona su problema.NamingStrategy
, de modo que sea capaz de analizar tanto el caso camel como el caso pascal?config
supone que es?config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
. Parece ser la API web de MVC 4HttpConfiguration
, consulte ¿Cómo configurar JsonSerializerSettings personalizados para Json.NET en la API web de MVC 4? .Esa es una muy buena respuesta. Pero, ¿por qué no anular el
ResolveDictionaryKey
?class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver { #region Overrides of DefaultContractResolver protected override string ResolveDictionaryKey(string dictionaryKey) { return dictionaryKey; } #endregion }
fuente
La respuesta seleccionada es perfecta, pero supongo que para cuando escribo esto, el solucionador de contratos debe cambiar a algo como esto porque DictionaryKeyResolver ya no existe :)
public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver { protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) { JsonDictionaryContract contract = base.CreateDictionaryContract(objectType); contract.PropertyNameResolver = propertyName => propertyName; return contract; } }
fuente
DictionaryKeyResolver
se agregó en la versión 7.0.1 yPropertyNameResolver
se marcó como obsoleto.