【问题标题】:Can save stream as local file, but when returning it as HttpResponseMessage - always empty file可以将流保存为本地文件,但是当它作为 HttpResponseMessage 返回时 - 始终为空文件
【发布时间】:2021-12-30 09:35:08
【问题描述】:

我想为来自外部 API 的文件编写导出/下载功能。 我已经为它创建了单独的动作。使用外部 API,我可以获得该文件的流。 当我将该流保存到本地文件时,一切都很好,文件不为空。

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);
}

但是当我返回包含streamexportedFile 对象并执行下一步时:

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;

导出的文件始终为空。

是流还是试图将该流作为文件返回的代码有问题?


尝试@Nobody 建议使用ToArray

fileResult.Content = new ByteArrayContent(ms.ToArray());

同样的结果。


也尝试使用StreamContent

fileResult.Content = new StreamContent(result.FileStream);

还是空文件。

但是当我使用StreamContentMemmoryStream

using (var ms = new MemoryStream())
{
     await result.FileStream.CopyToAsync(ms);
     ms.Position = 0;

     fileResult.Content = new StreamContent(ms);
}

结果我得到了

{ “错误”:“服务器没有响应” }


注意:我从 3rd 方 API 获得只读流。

【问题讨论】:

  • 为什么要改变 MemoryStream 的位置?
  • 你确定流不是空的吗?您可以在调试时检查它在 MemoryStream 上调用 ToArray() 并检查流有一些非 0 字节
  • @kalit,是的,流不为空。该流可以成功保存到本地计算机上的文件中,但是在响应返回时-它是空的
  • 请分享exportedFile.FileStream 的设置方式及其类型。另外,这个FileStream 属性在分配给ByteArrayContent 之前是否被读取/复制?
  • @pfx 我正在使用 PowerBI API 从仪表板获取文件流docs.microsoft.com/en-us/power-bi/developer/embedded/… 一切都如示例...只是 ExportedFile 对象转到调用该服务的 API 控制器。仅此而已。

标签: c# asp.net .net stream powerbi-embedded


【解决方案1】:

您使用 GetBuffer() 来检索内存流的数据。 您应该使用的函数是 ToArray() 请阅读这些函数的文档备注。

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()
}
    

【讨论】:

  • 试过了,但是文件还是空的...
【解决方案2】:

您的“错误”虽然很明显,但您返回了一条状态消息,而不是实际的文件本身(它自己也是 200)。

你返回这个:

var fileResult = new HttpResponseMessage(HttpStatusCode.OK);

因此,您发送的不是文件,而是响应消息。我在您的代码示例中缺少的是过程调用本身,但是由于您使用 HttpResonseMessage 我会假设它更像是一个普通的控制器操作。如果是这种情况,您可以以不同的方式回应:

return new FileContentResult(byteArray, mimeType){ FileDownloadName = filename };

其中 byteArray 当然只是一个 byte[],mimetype 可以是 application/octet-stream(但我建议您实际上找到正确的 mimetype 以供浏览器相应地执行),文件名是您想要的文件名要命名的文件。

所以,如果你把上面和我的评论拼接在一起,你会得到这个:

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 };

我建议尝试一下,因为您仍然报告 200(而不是文件结果)

【讨论】:

  • 不,它是 ApiController ......但我尝试了你的建议(使用 swagger),结果我只得到了 200 个 html 页面的响应
  • 什么html页面?
  • 我的布局没有任何内容
  • 我建议尝试添加代码(作为方法)
猜你喜欢
  • 1970-01-01
  • 2018-09-25
  • 1970-01-01
  • 2021-12-07
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-21
相关资源
最近更新 更多