En un controlador MVC normal, podemos generar pdf con a FileContentResult
.
public FileContentResult Test(TestViewModel vm)
{
var stream = new MemoryStream();
//... add content to the stream.
return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}
Pero, ¿cómo podemos convertirlo en un ApiController
?
[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
//...
return Ok(pdfOutput);
}
Esto es lo que he intentado pero no parece funcionar.
[HttpGet]
public IHttpActionResult Test()
{
var stream = new MemoryStream();
//...
var content = new StreamContent(stream);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Headers.ContentLength = stream.GetBuffer().Length;
return Ok(content);
}
El resultado devuelto que se muestra en el navegador es:
{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}
Y hay una publicación similar en SO: Devolver archivo binario del controlador en ASP.NET Web API . Habla sobre la salida de un archivo existente. Pero no pude hacerlo funcionar con una transmisión.
¿Alguna sugerencia?
c#
asp.net
asp.net-mvc
asp.net-web-api
Blaise
fuente
fuente
Respuestas:
En lugar de regresar
StreamContent
como elContent
, puedo hacer que funcioneByteArrayContent
.fuente
MemoryStream.GetBuffer()
realidad devuelve el búfer de MemoryStream, que generalmente es más grande que el contenido de la secuencia (para que las inserciones sean eficientes).MemoryStream.ToArray()
devuelve el búfer truncado al tamaño del contenido.byte[]
búfer? Sus usuarios pueden ejecutar fácilmente su aplicación sin memoria.Si quieres regresar
IHttpActionResult
puedes hacerlo así:fuente
Esta pregunta me ayudó.
Entonces, prueba esto:
Código del controlador:
Ver marcado HTML (con evento de clic y url simple):
fuente
FileStream
un archivo existente en el servidor. Es un poco diferente deMemoryStream
. Pero gracias por el aporte.FileStream
pero fallaMemoryStream
. Básicamente tiene que ver con el StreamPosition
.Aquí hay una implementación que transmite el contenido del archivo sin almacenarlo en el búfer (el almacenamiento en búfer en el byte [] / MemoryStream, etc. puede ser un problema del servidor si es un archivo grande).
Se puede usar simplemente así:
fuente
var fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
lugar deFile.OpenRead(FilePath)
No estoy exactamente seguro de qué parte culpar, pero he aquí por qué
MemoryStream
no funciona para usted:A medida que escribe
MemoryStream
, aumenta suPosition
propiedad. El constructor deStreamContent
tiene en cuenta la corriente de la corrientePosition
. Entonces, si escribe en la secuencia, páselo aStreamContent
, la respuesta comenzará desde la nada al final de la secuencia.Hay dos formas de arreglar esto correctamente:
1) construir contenido, escribir para transmitir
2) escribir para transmitir, restablecer posición, construir contenido
2) se ve un poco mejor si tiene una transmisión nueva, 1) es más simple si su transmisión no comienza en 0
fuente
Para mí fue la diferencia entre
y
El primero fue devolver la representación JSON de StringContent: {"Headers": [{"Key": "Content-Type", "Value": ["application / octet-stream; charset = utf-8"]}]}
Mientras que el segundo devolvía el archivo correctamente.
Parece que Request.CreateResponse tiene una sobrecarga que toma una cadena como el segundo parámetro y esto parece haber sido lo que estaba causando que el objeto StringContent se representara como una cadena, en lugar del contenido real.
fuente