c# - Mantenga la carcasa al serializar diccionarios
json.net (4)
Tengo un proyecto de API web configurado de la siguiente manera:
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 en Newtonsoft.Json
que pueda usar en una clase para indicar que quiero que la cubierta permanezca sin cambios durante la serialización?
public class SomeViewModel
{
public Dictionary<string, string> Data { get; set; }
}
Esa es una muy buena respuesta. Pero, ¿por qué no simplemente anula la ResolveDictionaryKey
?
class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver
{
#region Overrides of DefaultContractResolver
protected override string ResolveDictionaryKey(string dictionaryKey)
{
return dictionaryKey;
}
#endregion
}
La respuesta seleccionada es perfecta, pero supongo que para cuando escriba esto, el resuelve el contrato debe cambiar a algo así 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;
}
}
No hay un atributo para hacer esto, pero puede hacerlo personalizando el resolver.
Veo que ya está usando CamelCasePropertyNamesContractResolver
. Si obtiene una nueva clase de resolución de eso y anula el método CreateDictionaryContract()
, puede proporcionar una función sustituta de DictionaryKeyResolver
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. Tenga en cuenta que todos los nombres de las propiedades de la clase son de camel-cased, pero las claves del diccionario han conservado su carcasa original.
{
"anIntegerProperty": 42,
"htmlString": "<html></html>",
"dictionary": {
"WHIZbang": "1",
"FOO": "2",
"Bar": "3"
}
}
Json.NET 9.0.1 introdujo la jerarquía de clases NamingStrategy
para manejar este tipo de problema. Extrae la lógica para la reasignación algorítmica de los nombres de propiedades desde el resuelve de contratos a una clase separada y liviana que permite controlar si se reasignan claves de diccionario , nombres de propiedad explícitamente especificados y nombres de datos de extensión (en 10.0.1 ).
Al usar DefaultContractResolver
y al establecer NamingStrategy
en una instancia de CamelCaseNamingStrategy
, puede generar JSON con los nombres de las propiedades camel-cased y las claves del diccionario sin modificar:
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 de .Net con nombres de propiedades explícitamente especificados (por ejemplo, aquellos en los que se ha establecidoJsonPropertyAttribute.PropertyName
) deberían tener sus nombres reasignados:public CamelCasePropertyNamesContractResolver() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; }
La
resolver
anterior conserva este comportamiento. Si no quiere esto, configureOverrideSpecifiedNames = false
.Json.NET tiene varias estrategias de nomenclatura integradas que incluyen:
-
CamelCaseNamingStrategy
. Una estrategia de nomenclatura de camello que contiene la lógica de reasignación de nombres previamente incorporada enCamelCasePropertyNamesContractResolver
. -
SnakeCaseNamingStrategy
. Una estrategia de nombres de casos de serpientes . -
DefaultNamingStrategy
. La estrategia de nombres predeterminada. Los nombres de propiedades y las claves del diccionario no se modifican.
O bien, puede crear el suyo heredando de la clase base abstracta
NamingStrategy
.-
Si bien también es posible modificar
NamingStrategy
de una instancia deCamelCasePropertyNamesContractResolver
, ya que este último comparte información de contrato globalmente en todas las instancias de cada tipo , esto puede generar efectos secundarios inesperados si la aplicación intenta utilizar instancias múltiples deCamelCasePropertyNamesContractResolver
. No existe tal problema conDefaultContractResolver
, por lo que es más seguro usarlo cuando se requiere una personalización de la lógica de la carcasa.