Zip the whole ASP.NET Core application


This is a part of the series where about how I made the WebAPI2CLI - Execute ASP.NET Core WebAPI from Command Line
Source code on
1WebAPI2CLI - Description
2WebAPI2CLI- Organization
3WebAPI2CLI - implementing
4WebAPI2CLI - tests
5WebAPI2CLI - Devops and CI/CD
6WebAPI2CLI - documentation
7WebAPI2CLI - Conclusions
8WebAPI2CLI - Zip application

I realized that I should have somehow let the user play with the application from his PC. How can I do that , if the application is on some site  ? Answer: download the whole site as a zip file.

It should be relatively easy  for the user– so an endpoint routing should be used – something like “/zip”

It should be relatively easy  for the programmer – so I figured

app.UseEndpoints(endpoints =>

endpoints.MapZip(app); // IApplicationBuilder app

The code is also relativeley simple: enumerating recursive file and folders , creating the zip archive in memory, sending to the user

public static void MapZip(this IEndpointRouteBuilder endpoints, IApplicationBuilder app)
//see more at
endpoints.Map(“/zip”, async context =>
var response = context.Response;
var name = Assembly.GetEntryAssembly().GetName().Name + “.zip”;
response.ContentType = “application/octet-stream”;
var b = GetZip(app.ApplicationServices.GetService<IWebHostEnvironment>());
var contentDisposition = new Microsoft.Net.Http.Headers.ContentDispositionHeaderValue(“attachment”);
response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
await response.Body.WriteAsync(b);



private static Memory<byte> GetZip(IWebHostEnvironment env)
//var b = new Memory<byte>(Encoding.ASCII.GetBytes($”{env.ContentRootPath}”));
var firstDir = new DirectoryInfo(env.ContentRootPath);
var nameLength = firstDir.FullName.Length + 1;
using var memoryStream = new MemoryStream();
using var zipToOpen = new ZipArchive(memoryStream, ZipArchiveMode.Create, true);


foreach (FileInfo file in firstDir.RecursiveFilesAndFolders().Where(o => o is FileInfo).Cast<FileInfo>())
var relPath = file.FullName.Substring(nameLength);
var readmeEntry = zipToOpen.CreateEntryFromFile(file.FullName, relPath);
var b = new Memory<byte>(memoryStream.ToArray());
return b;


private static IEnumerable<FileSystemInfo> RecursiveFilesAndFolders(this DirectoryInfo dir)
foreach (var f in dir.GetFiles())
yield return f;
foreach (var d in dir.GetDirectories())
yield return d;
foreach (var o in RecursiveFilesAndFolders(d))
yield return o;


Some points to be noted:

1. It will work only if the site and user have the same operating system( assuming you have did self contained the .NET Core application)

2. ContentDispositionHeaderValue – exists in 2 libraries

3. I have shameless copy code from StackOverflow and github aspnet

4. I did not put in a separate library, nor I do automatic tests. Sorry, too tired

5. It works only if you put

endpoints.MapZip(app); // IApplicationBuilder app

If not, it does not zip!

6. IEndpointRouteBuilder – it is defined only you have the library .net core  3, not .net standard 2


<FrameworkReference Include=”Microsoft.AspNetCore.App” />