Quiero escribir la funcionalidad de exportación/descarga de archivos desde una API externa. He creado una Acción separada para ello. Usando una API externa, puedo obtener una transmisión para ese archivo. Cuando estoy guardando esa transmisión en un archivo local, todo está bien, el archivo no está vacío.
var exportedFile = await this.GetExportedFile(client, this.ReportId, this.WorkspaceId, export); // Now you have the exported file stream ready to be used according to your specific needs // For example, saving the file can be done as follows: string pathOnDisk = @"D:\Temp\" + export.ReportName + exportedFile.FileSuffix; using (var fileStream = File.Create(pathOnDisk)) { await exportedFile.FileStream.CopyToAsync(fileStream); } Pero cuando devuelvo el objeto exportedFile que contiene en su stream y hago lo siguiente:
var result = await this._service.ExportReport(reportName, format, CancellationToken.None); var fileResult = new HttpResponseMessage(HttpStatusCode.OK); using (var ms = new MemoryStream()) { await result.FileStream.CopyToAsync(ms); ms.Position = 0; fileResult.Content = new ByteArrayContent(ms.GetBuffer()); } fileResult.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = $"{reportName}{result.FileSuffix}" }; fileResult.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); return fileResult;El archivo exportado siempre está vacío.
¿Es un problema con la transmisión o con el código que intenta devolver esa transmisión como archivo?
Intenté como @Nobody sugiere usar ToArray
fileResult.Content = new ByteArrayContent(ms.ToArray());el mismo resultado
También traté de usar StreamContent
fileResult.Content = new StreamContent(result.FileStream);todavía archivo vacío.
Pero cuando uso StreamContent y MemmoryStream
using (var ms = new MemoryStream()) { await result.FileStream.CopyToAsync(ms); ms.Position = 0; fileResult.Content = new StreamContent(ms); }en resultado obtuve
{ "error": "sin respuesta del servidor" }
Nota: de la API de terceros obtengo una transmisión que es de solo lectura.
usó GetBuffer() para recuperar los datos del flujo de memoria. La función que debe usar es ToArray(). Lea los comentarios de la documentación de estas funciones.
https://docs.microsoft.com/en-us/dotnet/api/system.io.memorystream.getbuffer?view=net-6.0
using (var ms = new MemoryStream()) { ms.Position = 0; await result.FileStream.CopyToAsync(ms); fileResult.Content = new ByteArrayContent(ms.ToArray()); //ToArray() and not GetBuffer() }Su "error", aunque es obvio, es que devuelve un mensaje de estado, pero no el archivo en sí (que también es un 200).
Devuelves esto:
var fileResult = new HttpResponseMessage(HttpStatusCode.OK);Entonces no estás enviando un archivo, sino un mensaje de respuesta. Lo que me falta en sus ejemplos de código es la llamada al procedimiento en sí, pero dado que usa un HttpResonseMessage, asumiré que es más bien como una acción normal del controlador. Si ese es el caso, podrías responder de otra manera:
return new FileContentResult(byteArray, mimeType){ FileDownloadName = filename };donde byteArray es, por supuesto, solo un byte [], el mimetype podría ser application/octet-stream (pero sugiero que en realidad encuentre el mimetype correcto para que el navegador actúe en consecuencia) y el nombre de archivo es el nombre de archivo que desea que sea el archivo llamado.
Entonces, si tuviera que unir arriba y mi comentario juntos, obtendría esto:
var exportedFile = await this.GetExportedFile(client, this.ReportId, this.WorkspaceId, export); // Now you have the exported file stream ready to be used according to your specific needs // For example, saving the file can be done as follows: string pathOnDisk = @"D:\Temp\" + export.ReportName + exportedFile.FileSuffix; using (var fileStream = File.Create(pathOnDisk)) { await exportedFile.FileStream.CopyToAsync(fileStream); } return new FileContentResult(System.IO.File.ReadAllBytes(pathOnDisk), "application/octet-stream") { FileDownloadName = export.ReportName + exportedFile.FileSuffix };Sugiero probarlo, ya que aún informa un 200 (y no un resultado de archivo)