我有一个Web API端点,它通过首先下载文件,然后返回字节数组来为我提供文件.

此代码可以工作,但会首先将整个文件(无论它有多大)加载到内存中.

有没有办法简单地返回与我用来下载httpClient文件的流相同的流?

工作代码的简化示例:

[HttpGet("file")]
public async Task<IActionResult> DownloadFile(string url)
{
    using var httpClient = new HttpClient();
    using var response = await httpClient.GetAsync(url);
    if (response.IsSuccessStatusCode)
    {
        var content = await response.Content.ReadAsByteArrayAsync();

        var cd = new System.Net.Mime.ContentDisposition
        {
             FileName = "myFile.pdf",

             // always prompt the user for downloading, set to true if you want 
             // the browser to try to show the file inline
             Inline = false, 
        };
                
        Response.Headers.Add("Content-Disposition", cd.ToString());
                
        var mediaType = response.Content.Headers.ContentType.MediaType;

        return File(content, mediaType);
    }

    return NotFound();
}

我已经try 过的(也算是有效的):

using var httpClient = new HttpClient();
using var response = await httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
   using (var content = await response.Content.ReadAsStreamAsync())
   {
      content.Position = 0;

      var cd = new System.Net.Mime.ContentDisposition
      {
         FileName = "myFile.pdf",

         // always prompt the user for downloading, set to true if you want 
         // the browser to try to show the file inline
         Inline = false,
      };

      Response.Headers.Add("Content-Disposition", cd.ToString());

      var mediaType = response.Content.Headers.ContentType.MediaType;

      return File(content, mediaType);
}

但这给了我ObjectDisposedException: cannot access a closed stream美元.

请问有什么办法可以完成我想做的事吗?

推荐答案

为了同时处理多个请求,我在控制器类上添加了[ApiController]属性,并在DownloadFile操作方法中添加了[Produces("application/pdf")]属性.这允许同时高效地处理多个请求.

为了防止在发出多个请求时覆盖文件内容,我使用GUID for each 请求生成了一个唯一的文件名,并将其附加到文件名之后.这确保每个请求都有自己唯一的文件名,并且文件内容不会被覆盖.

生成的唯一文件名仅用于设置Content-Disposition标头中的文件名,该标头告诉用户浏览器如何处理下载的文件.

因此,文件实际上并不写入磁盘,而是直接流到响应流,并以具有唯一文件名的可下载附件的形式返回给用户.

EmptyResult类是ASP.NET Core中的内置类,表示状态代码为200的空响应.它用于操作不需要返回任何数据,但仍需要指示操作已成功完成的情况.

[ApiController]
public class FileController : ControllerBase
{
    [HttpGet("file")]
    [Produces("application/pdf")]
    public async Task<IActionResult> DownloadFile(string url)
    {
        using var httpClient = new HttpClient();
        var response = await httpClient.GetAsync(url);

        if (response.IsSuccessStatusCode)
        {
            var fileName = $"myFile_{Guid.NewGuid()}.pdf";
            var cd = new System.Net.Mime.ContentDisposition
            {
                FileName = fileName,
                Inline = false,
            };

            Response.Headers.Add("Content-Disposition", cd.ToString());
            var mediaType = response.Content.Headers.ContentType.MediaType;

            await response.Content.CopyToAsync(Response.Body);

            return new EmptyResult();
        }

        return NotFound();
    }
}

Csharp相关问答推荐

我无法在Program.cs中实例化我的学生类

EF Core. Income和. AsNoTracking正确用法

通过条件列表删除/更新EF Core 7中的实体的有效方法

为什么总输出就像12.3没有一分一样?

如果属性名为xyz,我需要使用System.Text.Json修改字符串类型的值""<>

ITypeLib2.GetLibStatistics()在C#中总是抛出AccessViolationException

在实时数据库中匹配两个玩家的问题

静态对象构造顺序

无法通过绑定禁用条目

我想在文本框悬停时在其底部显示一条线

由于POST中的应用程序/JWT,出现不支持的内容类型异常

Automapper 12.x将GUID映射到字符串

每个http请求需要60秒,为什么?

NET8 Maui&;iOS:AppCenter崩溃错误

ASP.NET Core MVC将值从视图传递到控制器时出现问题

在.NET 8最低API中从表单绑定中排除属性

当使用Dapper映射DBNull时,我可以抛出异常吗?

JSON串行化程序问题.SQLite中的空值

C#中类库项目的源代码生成器

忽略Visual Studio代码中的StyleCop规则