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