Home > Software design >  Problems with returning zip file
Problems with returning zip file

Time:06-24

I am writing an ASP.NET Core Web API with .NET 5.0 as an exercise.

In MyController.cs there is the method DownloadZip(). Here, it should be possible for the client to download a zip file. By the way, I create a zip file because I did not achieve to transfer multiple pictures. That is the actual goal. Provisionally, the zip file is still stored in the picture folder. Of course, that should not happen either. I simply still have difficulties with web services and transferring zip files via them.

Anyway, in the line return File(fullName, "text/plain"); I get the following error message:

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

I found several threads on StackOverflow last Friday about how to transfer a zip file using a memory stream. When I do it this way, the browser shows the individual bytes, but no finished file has been downloaded.

Postings is a list(of post) with

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

And Imageproperties is the following:

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

MyController.cs

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")] // Route will be https://localhost:44355/api/My/WhatAreTheNamesOfTheLatestPictures/
        public ActionResult GetNamesOfNewestPosting()
        {
            List<string> imageNames = this.imageRepository.GetImageNames();

            if (imageNames.Count == 0)
            {
                return NoContent();
            }
            return Ok(imageNames);
        }
        //––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
        [HttpGet("ImagesOfLatestPost")] //route will be https://localhost:44355/api/My/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);
                }
            }
            return File(fullName, "text/plain");
        }
    }
}

Edit June 20, 2022, 4:16 pm

Based on Bagus Tesa's comment, I wrote the following:

byte[] zip_as_ByteArray = System.IO.File.ReadAllBytes(fullName);

return File(zip_as_ByteArray, "application/zip");

The automatic download takes place, but I still have to rename the file by attaching (a) .zip so that Windows recognises it as a zip file.

enter image description here

Furthermore, there is still the problem that I am still creating the zip file on the hard disk (using (ZipArchive newFile = ZipFile.Open(fullName, ZipArchiveMode.Create))). How can I change this?

CodePudding user response:

Thanks to the thread linked by Bagus Tesa, I can now answer my question. I have adapted a few things to my needs, see for-loop, because I have several images.

[HttpGet("ImagesOfLatestPost")] //route will be https://localhost:44355/api/My/ImagesOfLatestPost
        public ActionResult DownloadZip()
        {
            List<Posting> Postings = this.imageRepository.GetImages();

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

            byte[] compressedBytes;
            using (var outStream = new System.IO.MemoryStream())
            {
                using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
                {
                    for (int i = 0; i < Postings[0].Imageproperties.Count; i  )
                    {
                        ZipArchiveEntry fileInArchive = archive.CreateEntry(Postings[0].Imageproperties[i]._Name, CompressionLevel.Optimal);
                        using System.IO.Stream entryStream = fileInArchive.Open();
                        using System.IO.MemoryStream fileToCompressStream = new System.IO.MemoryStream(Postings[0].Imageproperties[i].DataBytes);
                        fileToCompressStream.CopyTo(entryStream);
                    }  
                }
                compressedBytes = outStream.ToArray();
            }

            return File(compressedBytes, "application/zip", $"Export_{System.DateTime.Now:yyyyMMddhhmmss}.zip");
        }
  • Related