代码之家  ›  专栏  ›  技术社区  ›  demo

可以将流保存为本地文件,但当将其作为HttpResponseMessage返回时,始终为空文件

  •  0
  • demo  · 技术社区  · 4 年前

    我想从外部API为文件编写导出/下载功能。 我已经为它创建了单独的Action。使用外部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);
    }
    

    但当我回来的时候 exportedFile 包含在其中的对象 stream 然后执行下一步操作:

    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;
    

    导出的文件始终为空。

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


    尝试为@没有人建议使用 ToArray

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

    同样的结果。


    还尝试使用 StreamContent

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

    仍然为空的文件。

    但是当我使用 流内容 MemmoryStream

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

    结果我得到了

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


    注意:从第三方API我得到的流是只读的。

    0 回复  |  直到 4 年前
        1
  •  0
  •   demo    4 年前

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

    https://learn.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
  •  0
  •   riffnl    4 年前

    你的“错误”——尽管很明显——是你返回了一条状态消息,但没有返回实际的文件本身(它本身也是一个200)。

    您返回此:

    var fileResult = new HttpResponseMessage(HttpStatusCode.OK);
    

    所以你不是在发送一个文件,而是在发送一条响应消息。在您的代码示例中,我缺少的是过程调用本身,但由于您使用了HttpResonseMessage,我认为它更像是一个普通的Controller操作。如果是这种情况,你可以用不同的方式回应:

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

    其中byteArray当然只是一个byte[],mimetype可以是application/octet流(但我建议您实际找到正确的mimetype,以便浏览器相应地执行操作),而filename就是您希望命名文件的文件名。

    所以,如果你把上面和我的评论缝合在一起,你会得到这样的结果:

    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(而不是fileresult)

    推荐文章