De casualidad me he topado con un interesante cambio que .NET 5 introdujo en los componentes de serialización y deserialización System.Text.Json
y que, al menos para mí, pasó totalmente desapercibido en su momento. Por eso, he pensado que quizás sea buena idea dejarlo por aquí, por si hay algún despistado más al que pueda resultar útil.
Como seguro sabéis, al usar los componentes de System.Text.Json
para serializar o deserializar una clase, utilizamos el atributo [JsonIgnore]
para marcar las propiedades que queremos que sean ignoradas al convertir desde y hacia JSON.
Por ejemplo, dada la siguiente clase:
class User
{
public int Id { get; set; }
public string Email { get; set; }
[JsonIgnore]
public string Token { get; set; }
}
En ella estamos indicando expresamente que la propiedad Token
debe ser ignorada, por lo que ésta no aparecerá si serializamos un objeto a JSON:
var user = new User { Id = 42, Email = "john@server.com", Token = "ABCDEF"};
Console.WriteLine(JsonSerializer.Serialize(user));
// Result:
{"Id":42,"Email":"john@server.com"}
Y lo mismo ocurre en sentido contrario:
var jsonStr = "{ \"Id\": 42, \"Email\": \"john@server.com\", \"Token\": \"ABCDEF\"}";
var user = JsonSerializer.Deserialize<User>(jsonStr);
// ¡user.Token es nulo aquí!
La novedad introducida en .NET 5 es que JsonIgnore
ahora soporta un parámetro de tipo JsonIgnoreCondition
que permite especificar ciertas condiciones para que la propiedad afectada sea ignorada, por ejemplo:
class User
{
public int Id { get; set; }
public string Email { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Token { get; set; }
}
JsonIgnoreCondition
es un enumerado con los siguientes miembros, cuya utilidad puede intuirse simplemente al verlos:
public enum JsonIgnoreCondition
{
Never,
Always,
WhenWritingDefault,
WhenWritingNull,
}
El valor Never
indica que la propiedad no debe ignorarse nunca, por lo que será equivalente a no decorarla con [JsonIgnore]
.
Always
indica que la propiedad debe ser ignorada siempre, así que es el equivalente a decorar con [JsonIgnore]
a secas.
Con WhenWritingDefault
indicamos que la propiedad debe ser ignorada cuando se trate de escribir (serializar) el valor por defecto del tipo de datos de la misma. Por ejemplo, en el siguiente código, la serialización omitirá la propiedad id
cuando ésta valga cero (el valor por defecto del tipo int
):
class User
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Id { get; set; }
public string Email { get; set; }
}
var user = new User { Email = "john@server.com" };
Console.WriteLine(JsonSerializer.Serialize(user));
var user42 = new User { Id=42, Email = "peter@server.com" };
Console.WriteLine(JsonSerializer.Serialize(user42));
// Result:
{"Email":"john@server.com"}
{"Id":42, "Email":"peter@server.com"}
De forma muy similar, WhenWritingNull
omitirá la serialización de la propiedad cuando su valor sea nulo.
class User
{
public string Email { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Token { get; set; }
}
var userWithToken = new User { Email = "john@server.com", Token="ABCDEF" };
Console.WriteLine(JsonSerializer.Serialize(userWithToken));
var userWithoutToken = new User { Email = "peter@server.com" };
Console.WriteLine(JsonSerializer.Serialize(userWithoutToken));
// Result:
{"Email":"john@server.com","Token":"ABCDEF"}
{"Email":"peter@server.com"}
Fijaos que en tipos referencia como un
string
,WhenWritingNull
yWhenWritingDefault
son equivalentes.
En definitiva, no es algo que no pudiéramos hacer antes con un pequeño conversor personalizado, pero ciertamente así lo tenemos más a mano :)
Publicado en Variable not found.
2 Comentarios:
Hola!
y si quisiéramos que JsonIgnore fuera condicional?
haciendo pruebas, y asignando "[JsonIgnore(Condition = LlamadaAUnaFuncion())]" da un error en compilación, ya que únicamente permite valores constantes.
Hay forma de de condicionarlo?
Un abrazo.
Hola!
El atributo no soporta esa posibilidad, y tampoco podemos heredar de él para hacer una implementación personalizada.
Pero quizás podrías conseguir lo que pretendes usando un conversor personalizado. Puedes leer algo sobre ellos aquí: Deserialización y serialización personalizada en .NET con System.Text.Json usando custom converters.
La forma de hacerlo depende de la lógica que quieras aplicar para decidir la forma de serialización. Podrías crear un custom serializador para la clase completa, o hacerlo para aplicarlo en campos individuales con [JsonConverter].
Saludos!
Enviar un nuevo comentario