You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 5.0 ASP.NET Core Web API返回ZIP文件异常排查

.NET 5.0 ASP.NET Core Web API ZIP下载问题修复

问题背景

  • 项目场景:练习开发基于.NET 5.0的ASP.NET Core Web API项目,需要实现多图片传输功能,临时采用ZIP打包下载方案
  • 初始异常:执行return File(fullName, "text/plain");代码时抛出错误:

System.InvalidOperationException: No file provider has been configured to process the supplied file.

  • 中间迭代问题:尝试内存流传ZIP方案时,浏览器直接展示字节数据未触发下载;调整为读取本地ZIP转字节数组返回application/zip类型后可触发下载,但存在两个遗留问题:
    • 下载的文件默认不带.zip后缀,需要手动追加才能被Windows识别为压缩包
    • 实现过程会在系统图片文件夹生成本地临时ZIP文件,存在冗余磁盘IO

关联实体定义

Posting实体

using System;
using System.Collections.Generic;

namespace ImageRepository
{
    public sealed class Posting
    {
        public DateTime CreationTime { get; set; }
        public List<ImageProperties> Imageproperties { get; }

        public Posting(DateTime creationTime, List<ImageProperties> imPr)
        {
            CreationTime = creationTime;
            Imageproperties = imPr;
        }
    }
}

ImageProperties实体

namespace ImageRepository
{
    public sealed class ImageProperties
    {
        public string FullName { get; set; }
        public string _Name { get; set; }
        public byte[] DataBytes { get; set; }

        public ImageProperties(string FullName, string Name, byte[] dataBytes)
        {
            this.FullName = FullName;
            this._Name = Name;
            this.DataBytes = dataBytes;
        }
    }
}

原有问题代码

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using ImageRepository;
using System.IO.Compression;

namespace WebApp2.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class MyController : ControllerBase
    {
        private readonly IImageTransferRepository imageRepository;
        private readonly System.Globalization.CultureInfo Deu = new System.Globalization.CultureInfo("de-DE");

        public MyController(IImageTransferRepository imageTransferRepository)
        {
            this.imageRepository = imageTransferRepository;
        }

        [HttpGet("WhatAreTheNamesOfTheLatestPictures")]
        public ActionResult GetNamesOfNewestPosting()
        {
            List<string> imageNames = this.imageRepository.GetImageNames();

            if (imageNames.Count == 0)
            {
                return NoContent();
            }
            return Ok(imageNames);
        }

        [HttpGet("ImagesOfLatestPost")]
        public ActionResult DownloadZip()
        {
            List<Posting> Postings = this.imageRepository.GetImages();

            if (Postings is null || Postings.Count == 0)
            {
                return NoContent();
            }

            System.DateTime now = System.DateTime.Now;
            string now_as_string = now.ToString("G", Deu).Replace(':', '-');
            string folderPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures);
            string fullName = $"{folderPath}\\{now_as_string}.zip";
            using (ZipArchive newFile = ZipFile.Open(fullName, ZipArchiveMode.Create))
            {
                for (int i = 0; i < Postings[0].Imageproperties.Count; i++)
                {
                    newFile.CreateEntryFromFile(Postings[0].Imageproperties[i].FullName,
                                                Postings[0].Imageproperties[i]._Name);
                }
            }
            byte[] zip_as_ByteArray = System.IO.File.ReadAllBytes(fullName);
            return File(zip_as_ByteArray, "application/zip");
        }
    }
}

修复实现

核心修复点

  • 解决文件无后缀问题:使用File方法的三参数重载,第三个参数传入带.zip后缀的下载文件名,浏览器会自动按该名称保存文件,无需手动修改后缀
  • 解决本地临时文件问题:替换本地文件写入逻辑为内存流MemoryStream承载ZIP压缩内容,压缩全程在内存完成,不会在磁盘生成任何临时文件
  • 额外优化:优先使用ImageProperties中已存储的DataBytes字节数组写入压缩包,避免重复读取磁盘文件,降低IO开销

修复后DownloadZip方法代码

[HttpGet("ImagesOfLatestPost")]
public ActionResult DownloadZip()
{
    List<Posting> Postings = this.imageRepository.GetImages();

    if (Postings is null || Postings.Count == 0)
    {
        return NoContent();
    }

    DateTime now = DateTime.Now;
    string now_as_string = now.ToString("G", Deu).Replace(':', '-');
    string downloadFileName = $"{now_as_string}.zip";
    
    using (MemoryStream zipStream = new MemoryStream())
    {
        // leaveOpen设为true,避免ZipArchive释放时关闭内存流
        using (ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true))
        {
            foreach (var img in Postings[0].Imageproperties)
            {
                ZipArchiveEntry entry = archive.CreateEntry(img._Name, CompressionLevel.Optimal);
                using (Stream entryStream = entry.Open())
                {
                    // 优先使用已加载的图片字节,不存在时再读取本地文件
                    byte[] imgContent = img.DataBytes ?? System.IO.File.ReadAllBytes(img.FullName);
                    entryStream.Write(imgContent, 0, imgContent.Length);
                }
            }
        }
        // 返回压缩包字节数组,指定正确MIME类型和下载文件名
        return File(zipStream.ToArray(), "application/zip", downloadFileName);
    }
}

注意事项

  • 所有流对象都用using包裹,方法执行完成后会自动释放资源,不会造成内存泄漏
  • MIME类型使用标准application/zip,主流浏览器均可正确识别并触发文件下载,不会直接在页面展示字节内容

内容的提问来源于stack exchange,提问作者Daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:42:21