Saltar al contenido

La operación no es válida debido al estado actual del objeto (System.Text.Json)

Solución:

Su problema se puede reproducir con el siguiente ejemplo más mínimo. Defina el siguiente modelo:

public class JsonApiMessage

    public JsonElement data  get; set; 

Luego intente deserializar y volver a serializar un objeto JSON vacío así:

var payload = JsonSerializer.Deserialize("");
var newJson = JsonSerializer.Serialize(payload, new JsonSerializerOptions  WriteIndented = true );

Y obtendrá una excepción (demo violín n. ° 1 aquí):

System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at System.Text.Json.JsonElement.WriteTo(Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.JsonConverterJsonElement.Write(Utf8JsonWriter writer, JsonElement value, JsonSerializerOptions options)

El problema parece ser que JsonElement es un structy el valor predeterminado de esta estructura no se puede serializar. De hecho, simplemente haciendo JsonSerializer.Serialize(new JsonElement()); lanza la misma excepción (demo violín # 2 aquí). (Esto contrasta con JObject que es un tipo de referencia cuyo valor predeterminado es, por supuesto, null.)

¿Entonces cuales son tus opciones? Podrías hacer todo tu JsonElement las propiedades sean anulables y se establezcan IgnoreNullValues = true mientras se vuelve a serializar:

public class JsonApiData

    [JsonPropertyName("type")]
    public string Type  get; set; 

    [JsonPropertyName("id")]
    public string Id  get; set; 

    [JsonPropertyName("attributes")]
    public JsonElement? Attributes  get; set; 

    [JsonPropertyName("meta")]
    public JsonElement? Meta  get; set; 

    [JsonPropertyName("relationships")]
    public JsonElement? Relationships  get; set; 

Y luego:

var reserialisedPayload  = JsonSerializer.Serialize(payload, new JsonSerializerOptions  IgnoreNullValues = true );

Demostración del violín n. ° 3 aquí.

O en .NET 5 o posterior, puedes marcar todos tus JsonElement propiedades con [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]:

public class JsonApiData

    // Remainder unchanged

    [JsonPropertyName("attributes")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public JsonElement Attributes  get; set; 

    [JsonPropertyName("meta")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public JsonElement Meta  get; set; 

    [JsonPropertyName("relationships")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
    public JsonElement Relationships  get; set; 

Si lo hace, los elementos no inicializados se omitirán durante la serialización sin necesidad de modificar las opciones de serialización.

Demostración del violín n. ° 4 aquí.

O bien, puede simplificar su modelo de datos vinculando todas las propiedades JSON que no sean Id a un JsonExtensionData propiedad como tal:

public class JsonApiData

    [JsonPropertyName("id")]
    public string Id  get; set; 

    [JsonExtensionData]
    public Dictionary ExtensionData  get; set; 

Este enfoque evita la necesidad de configurar manualmente IgnoreNullValues al volver a serializar y, por lo tanto, ASP.NET Core volverá a serializar el modelo correctamente de forma automática.

Demostración del violín n. ° 5 aquí.

La excepción es correcta: el estado del objeto no es válido. los Meta y Relasionships los elementos no aceptan valores NULL, pero el JSON string no los contiene. los Delawareel objeto serializado termina con Undefined valores en esas propiedades que no se pueden serializar.

    [JsonPropertyName("meta")]
    public JsonElement? Meta  get; set; 

    [JsonPropertyName("relationships")]
    public JsonElement? Relationships  get; set; 

La solución rápida sería cambiar esas propiedades a JsonElement?. Esto permitirá una deserialización y serialización correctas. De forma predeterminada, los elementos faltantes se emitirán como nulos:

"meta": null,
"relationships": null

Para ignorarlos, agregue el IgnoreNullValues =true opción :

var newJson = JsonSerializer.Serialize(payload, new JsonSerializerOptions 
                            WriteIndented = true,IgnoreNullValues =true );

los verdadero Sin embargo, la solución sería deshacerse de todo ese código. Eso cestas el uso de System.Text.Json. Dejado por sí mismo, ASP.NET Core usa Pipelines para leer el flujo de entrada sin asignar, deserializa la carga útil y llama al método con el objeto deserializado como parámetro, utilizando asignaciones mínimas. Todos los valores devueltos se serializan de la misma manera.

Sin embargo, el código de la pregunta asigna mucho: almacena en caché la entrada en StreamReader, luego toda la carga útil se almacena en caché en el payloadString y luego otra vez, como el payload objeto. El proceso inverso también utiliza cadenas temporales. Este código toma por lo menos el doble de RAM de la que usaría ASP.NET Core.

El código de acción debe ser solo:

[HttpPost("eventType")]
public async Task ProcessEventAsync([FromRoute] string eventType,
                                                   MyApiData payload)

    Guid messageID = Guid.NewGuid();
    payload.Data.Id = messageID.ToString();

    return Accepted(payload);

Dónde MyApiData es un objeto fuertemente tipado. La forma del ejemplo de Json corresponde a:

public class Attributes

    public string source  get; set; 
    public string instance  get; set; 
    public string level  get; set; 
    public string message  get; set; 


public class Data

    public string type  get; set; 
    public Attributes attributes  get; set; 


public class MyApiData

    public Data data  get; set; 
    public Data[] included get;set;

Todas las demás comprobaciones las realiza ASP.NET Core; ASP.NET Core rechazará cualquier POST que no tiene el tipo MIME correcto. Devolverá un 400 si la solicitud está mal formateada. Devolverá un 500 si el código arroja

Nos puedes sustentar nuestra investigación poniendo un comentario y puntuándolo te estamos agradecidos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *