PDA

Ver la versión completa : C# Clonar un HttpContent



Drumpi
06/09/2022, 18:45
Hola a todos:

Yo con esto del Http y los streams de datos me lío un montón. Son cosas que he ido aprendiendo sobre la marcha y no tengo una base sólida. Resulta que estoy mandando datos a una WebApi, para ello creo un HttpContent tal que así:


HttpContent content = new StringContent(JsonConvert.SerializeObject(miObject ), System.Text.Encoding.UTF8, "application/json");

Luego uso ese HttpContent para llamar a un método que envía los datos con un PostAsync:


HttpClient client = (un chorizo);
HttpResponseMessage response = await client.PostAsync(requestUri, content);

El problema que tengo es que, a veces, ha pasado tanto tiempo desde el último mensaje que la WebApi ha cerrado la sesión, y no me entero hasta que me llega la respuesta con el código 401 o 403. Vale, no pasa nada: se envían los datos de login, y cuando se abra la sesión, repito el envío ¿no?
Pues no, el PostAsync, tras el envío, borra (dispose) el contenido del HttpContent, y esto me provoca una excepción que estoy tratando de solucionar.

Como el PostAsync está en un método que se usa en todo el código, no puedo cambiar el parámetro de entrada de HttpContent a object, porque tendría como 40 llamadas que modificar. Así que he pensado que es mejor crear un clon del HttpClient, y enviar este en su lugar. De esta forma, si falla el envío, puedo crear una nueva copia y volver a enviar la información.

El problema es que HttpClient no tiene función Clone(). Se supone que debería deserializar el contenido, o convertirlo en un Stream, o en un byte array o en algo, y usar eso para generar un nuevo HttpContent... y eso es lo que no sé cómo hacer. Puedo crear un StreamArray, pero luego no hay forma de meterlo en el HttpContent, o un byte array, o un string... y no sé si se puede deserializar de nuevo en el objeto original para volver a serializarlo en un JSON, o si esa idea requiere dos conversiones que no son necesarias porque hay una forma más sencilla de hacerlo.

Llevo muchas páginas de ayuda leídas y ninguna me resuelve la duda. A ver si alguien entre vosotros me puede echar una mano, por favor.

pakoito
06/09/2022, 21:24
Como el PostAsync está en un método que se usa en todo el código, no puedo cambiar el parámetro de entrada de HttpContent a object, porque tendría como 40 llamadas que modificar.Esa es la solución, aunque a veces duela. Si usas Visual Studio o IntelliJ debería haber una opción de refactorizar esto llamada Refactor -> Signature, o directamente extrayendo el Objeto a un parámetro. Para el resto, expresiones regulares para reemplazar el código.

Drumpi
07/09/2022, 10:37
Esa es la solución, aunque a veces duela. Si usas Visual Studio o IntelliJ debería haber una opción de refactorizar esto llamada Refactor -> Signature, o directamente extrayendo el Objeto a un parámetro. Para el resto, expresiones regulares para reemplazar el código.

Mmmmm, el problema que tengo con esa solución es que es peligrosa, ya no porque haya tropecientas llamadas o lo que sea, sino porque como lo que necesito es leer un object, el HttpContent es un object, y no me va a cantar el error, y con uno solo que se me olvide, ya tendremos problemas. Habría que testear toda la app al completo (ya sé que hay sistemas de testeo automático, pero no los hay para crear los datos necesarios con los que trabajar, y hay que hacerlos a mano).

Pero si no hay otro modo, tendré que hacerlo así. Es raro que no se pueda copiar un objeto, o su contenido.

Drumpi
08/09/2022, 17:09
Al final es la solución que he acabado adoptando. Lo he testeado y lo he revisado bien y parece que no hay problemas.
Pero veo que no he sido el único que se ha quejado de esto, que el response haga disposal del HttpContent. El caso es que funcionaba bien antes de actualizar las librerías (y hablo de 3 años de diferencia). Luego preguntan por qué hay gente que no actualiza el código...

MasterGame
11/09/2022, 00:52
Eso puede tener freeze