Si bien encontré muchos enfoques para deserializar propiedades específicas y evitar que se serialicen, estoy buscando el comportamiento opuesto.
He encontrado muchas preguntas que hacen lo contrario:
Hacer que una propiedad se deserialice pero no se serialice con json.net
¿Puedo indicar a Json.NET que deserialice, pero no serialice, propiedades específicas?
JSON.Net: use JsonIgnoreAttribute solo en la serialización (pero no al deserializar)
¿Cómo puedo serializar una propiedad específica, pero evitar que se deserialice de nuevo al POCO? ¿Hay algún atributo que pueda usar para decorar la propiedad específica?
Básicamente, estoy buscando un equivalente a los métodos ShouldSerialize* para la deserialización.
Sé que puedo escribir un convertidor personalizado, pero parece una exageración para esto.
Editar:
Aquí hay un poco más de contexto. La razón detrás de esto es que mi clase se ve así:
public class Address : IAddress { /// <summary> /// Gets or sets the two character country code /// </summary> [JsonProperty("countryCode")] [Required] public string CountryCode { get; set; } /// <summary> /// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c> /// </summary> [JsonProperty("countryProvinceState")] public string CountryProvinceState { get { return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState); } set { if (!string.IsNullOrWhiteSpace(value) && value.Contains("|")) { string[] valueParts = value.Split('|'); if (valueParts.Length == 2) { this.CountryCode = valueParts[0]; this.ProvinceState = valueParts[1]; } } } } [JsonProperty("provinceState")] [Required] public string ProvinceState { get; set; } }
Necesito la propiedad CountryProvinceState
para la solicitud, pero no quiero que se deserialice y active la lógica de establecimiento.
El método más simple sería marcar la propiedad real como [JsonIgnore]
y crear una propiedad proxy de solo obtención:
/// <summary> /// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c> /// </summary> [JsonIgnore] public string CountryProvinceState { get { return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState); } set { if (!string.IsNullOrWhiteSpace(value) && value.Contains("|")) { string[] valueParts = value.Split('|'); if (valueParts.Length == 2) { this.CountryCode = valueParts[0]; this.ProvinceState = valueParts[1]; } } } } [JsonProperty("countryProvinceState")] string ReadCountryProvinceState { get { return CountryProvinceState; } }
La propiedad del proxy puede ser privada si lo desea.
Actualizar
Si tiene que hacer esto para muchas propiedades en muchas clases, podría ser más fácil crear su propio ContractResolver
que verifique un atributo personalizado. Si se encuentra, el atributo indicaría que la propiedad es de solo obtención:
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)] public class GetOnlyJsonPropertyAttribute : Attribute { } public class GetOnlyContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if (property != null && property.Writable) { var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true); if (attributes != null && attributes.Count > 0) property.Writable = false; } return property; } }
Entonces úsalo como:
[JsonProperty("countryProvinceState")] [GetOnlyJsonProperty] public string CountryProvinceState { get; set; }
Y luego:
var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() }; var address = JsonConvert.DeserializeObject<Address>(jsonString, settings);
En su pregunta, tiene una propiedad de cadena simple. Pero es un poco más complicado cuando tienes un objeto. La solución con .Writeable = false
no funcionará, ya que la deserialización irá a las propiedades de un objeto. Considere el siguiente código:
public class Constants { public Address Headquarters { get; set; } public static Constants Instance = new Constants { Headquarters = new Address { Street = "Baker Street" } }; } public class Address { public string Street { get; set; } } public class Data { [GetOnlyJsonProperty] // we want this to be included in the response, but not deserialized back public Address HqAddress { get { return Constants.Instance.Headquarters; } } } // somewhere in your code: var data = JsonConvert.DeserializeObject<Data>("{'HqAddress':{'Street':'Liverpool Street'}}", settings);
Ahora JSON aún no intentará crear un nuevo objeto de HqAddress
Addreess
ya que solo tiene un captador. Pero luego (aunque .Writeable == false
) profundiza y deserializa la propiedad Street
, configurando "Liverpool Street" en el objeto Constants.Instance.Heqdquarters
, sobrescribiendo los datos en las Constantes de su aplicación.
La solución es : en una nueva versión de Newtonsoft.JSON (lo probé en v10), hay una nueva propiedad ShouldDeserialize
. Entonces el resolutor debería ser:
public class GetOnlyContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if (property != null) // Change here (1) { var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true); if (attributes != null && attributes.Count > 0) property.ShouldDeserialize = (a) => false; // Change here (2) } return property; } }
(1) Eliminé la condición para && property.Writeable
, por lo que procesa HqAddress
y omite la deserialización para un árbol completo. (2) ShouldDeserialize
es un predicado, invocado en cada objeto para deserializar. Por lo tanto, puede omitir condicionalmente solo algunas propiedades. Pero aquí lo hice simple, por ejemplo.