c# - parametros - Obtener datos de POST sin procesar desde el método de la API web
enviar json por url (5)
Tengo el siguiente método de API web en una clase ApiController:
public HttpResponseMessage Post([FromBody]byte[] incomingData)
{
...
}
Quiero que incomingData
sea el contenido sin formato del POST. Pero parece que la pila API Web intenta analizar los datos entrantes con el formateador JSON, y esto hace que el siguiente código en el lado del cliente falle:
new WebClient().UploadData("http://localhost:15134/api/Foo", new byte[] { 1, 2, 3 });
¿Hay una solución simple para esto?
En MVC 6 Request no parece tener una propiedad ''Content''. Esto es lo que terminé haciendo:
[HttpPost]
public async Task<string> Post()
{
string content = await new StreamReader(Request.Body).ReadToEndAsync();
return "SUCCESS";
}
Las otras respuestas sugieren eliminar el parámetro de entrada, pero eso romperá todo su código existente. Para responder la pregunta correctamente, una solución más fácil es crear una función que se vea así (gracias a Christoph a continuación para este código):
private async Task<String> getRawPostData()
{
using (var contentStream = await this.Request.Content.ReadAsStreamAsync())
{
contentStream.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(contentStream))
{
return sr.ReadToEnd();
}
}
}
y luego obtenga los datos sin procesar publicados dentro de su llamada a la API web de la siguiente manera:
public HttpResponseMessage Post ([FromBody]byte[] incomingData)
{
string rawData = getRawPostData().Result;
// log it or whatever
return Request.CreateResponse(HttpStatusCode.OK);
}
Para cualquier otra persona que se encuentre con este problema, la solución es definir el método POST sin parámetros y acceder a los datos brutos a través de Request.Content
:
public HttpResponseMessage Post()
{
Request.Content.ReadAsByteArrayAsync()...
...
Si necesita la entrada sin procesar además del parámetro del modelo para facilitar el acceso, puede usar lo siguiente:
using (var contentStream = await this.Request.Content.ReadAsStreamAsync())
{
contentStream.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(contentStream))
{
string rawContent = sr.ReadToEnd();
// use raw content here
}
}
El secreto es usar stream.Seek(0, SeekOrigin.Begin)
para reiniciar la transmisión antes de intentar leer los datos.
Tomé la respuesta de LachlanB y la puse en una clase de utilidad con un único método estático que puedo usar en todos mis controladores.
public class RawContentReader
{
public static async Task<string> Read(HttpRequestMessage req)
{
using (var contentStream = await req.Content.ReadAsStreamAsync())
{
contentStream.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(contentStream))
{
return sr.ReadToEnd();
}
}
}
}
Entonces puedo llamarlo desde cualquiera de mis métodos de ApiController de esta manera:
string raw = await RawContentReader.Read(this.Request);