tutorial example ejemplo consumir c# asp.net asp.net-mvc asp.net-web-api

example - web api rest c# tutorial



Cómo devolver un archivo(FileContentResult) en ASP.NET WebAPI (5)

En un controlador MVC regular, podemos generar PDF con 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 cambiarlo a un ApiController ?

[HttpPost] public IHttpActionResult Test(TestViewModel vm) { //... return Ok(pdfOutput); }

Esto es lo que he intentado, pero parece que no funciona.

[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 el archivo binario del controlador en ASP.NET Web API . Habla de salida un archivo existente. Pero no pude hacer que funcione con una transmisión.

¿Alguna sugerencia?


En lugar de devolver StreamContent como Content , puedo hacerlo funcionar con ByteArrayContent .

[HttpGet] public HttpResponseMessage Generate() { var stream = new MemoryStream(); // processing the stream. var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(stream.ToArray()) }; result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = "CertificationCard.pdf" }; result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); return result; }


No estoy seguro de cuál es la parte culpable, pero esta es la razón por la cual MemoryStream no funciona para usted:

Al escribir en MemoryStream , incrementa su propiedad Position . El constructor de StreamContent tiene en cuenta la Position actual de la secuencia. Entonces, si escribe en la transmisión y luego la pasa a StreamContent , la respuesta comenzará desde la nada al final de la transmisión.

Hay dos formas de corregir esto correctamente:

1) construir contenido, escribir en la secuencia

[HttpGet] public HttpResponseMessage Test() { var stream = new MemoryStream(); var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StreamContent(stream); // ... // stream.Write(...); // ... return response; }

2) escribir en la secuencia, restablecer la posición, construir el contenido

[HttpGet] public HttpResponseMessage Test() { var stream = new MemoryStream(); // ... // stream.Write(...); // ... stream.Position = 0; var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StreamContent(stream); return response; }

2) parece un poco mejor si tienes un Stream nuevo, 1) es más simple si tu transmisión no comienza en 0


Para mí fue la diferencia entre

var response = Request.CreateResponse(HttpStatusCode.OK, new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

y

var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(log, System.Text.Encoding.UTF8, "application/octet-stream");

El primero devolvía la representación JSON de StringContent: {"Headers": [{"Key": "Content-Type", "Value": ["application / octet-stream; charset = utf-8"]}]}

Mientras que el segundo devolvió el archivo propiamente dicho.

Parece que Request.CreateResponse tiene una sobrecarga que toma una cadena como el segundo parámetro y parece que esto fue lo que estaba causando que el objeto StringContent en sí se procesara como una cadena, en lugar del contenido real.


Si desea devolver IHttpActionResult , puede hacerlo así:

[HttpGet] public IHttpActionResult Test() { var stream = new MemoryStream(); var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(stream.GetBuffer()) }; result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = "test.pdf" }; result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); var response = ResponseMessage(result); return response; }


This pregunta me ayuda.

Por lo tanto, intente esto:

Código del controlador:

[HttpGet] public HttpResponseMessage Test() { var path = System.Web.HttpContext.Current.Server.MapPath("~/Content/test.docx");; HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); var stream = new FileStream(path, FileMode.Open); result.Content = new StreamContent(stream); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(path); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); result.Content.Headers.ContentLength = stream.Length; return result; }

Ver marcado de Html (con evento click y url simple):

<script type="text/javascript"> $(document).ready(function () { $("#btn").click(function () { // httproute = "" - using this to construct proper web api links. window.location.href = "@Url.Action("GetFile", "Data", new { httproute = "" })"; }); }); </script> <button id="btn"> Button text </button> <a href=" @Url.Action("GetFile", "Data", new { httproute = "" }) ">Data</a>