Reputation: 893
When it comes to downloading files from server to client in blazor, there does not seem to be a best practice yet (please correct me if I am wrong). One good solution seems to be to implement a controller that returns a filestream (like it is done here: How to download in-memory file from Blazor server-side), there are also more client-side oriented solutions that involve javascript (like these: How can one generate and save a file client side using Blazor?). None of these however seem to exactly fit my problem.
What I want is a solution that lets me start parallel download streams of big files from the server to the client. Currently I am using a controller that fetches and zips files from a given directory in memory. I want the user to be able to start multiple download streams from the same page client-side. This does not work with my controller currently, since it redirects the user and the user has to wait until the download is finished to start the next. What is a good way to offer parallel downloads in blazor?
Here is what I currently have (simplified):
Controller:
[ApiController]
[Route("[controller]")]
public class DownloadController : Controller
{
[HttpGet("{directory}/{zipFileName}")]
[DisableRequestSizeLimit]
public IActionResult DownloadZipFile(string directory, string zipFileName)
{
directory = System.Net.WebUtility.UrlDecode(directory);
if (Directory.Exists(directory))
{
using (ZipFile zip = new ZipFile())
{
var files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (var f in files)
{
zip.AddFile(f,Path.GetDirectoryName(f).Replace(directory, string.Empty));
}
using (MemoryStream memoryStream = new MemoryStream())
{
zip.Save(memoryStream);
return File(memoryStream.ToArray(), "application/zip", String.Format(zipFileName));
}
}
}
else
{
// error handling
}
}
}
Razor Page:
<button @onclick="()=>DownloadZip(zipFilePath)">download file</button>
@code {
protected string zipFilePath= @"C:\path\to\files";
protected void DownloadZip(string zipFilePath)
{
NavigationManager.NavigateTo("api/download/" + System.Net.WebUtility.UrlEncode(zipFilePath) + "/ZipFileName.zip", true);
}
}
Upvotes: 0
Views: 604
Reputation: 8994
Don't use a button and NavigationManager - instead use an anchor tag with the download attribute:
<a href=@GetZipURL(zipFilePath) target="_new" download>download file</a>
@code {
protected string zipFilePath= @"C:\path\to\files";
protected string GetZipURL(string zipFilePath)
{
return $"api/download/{System.Net.WebUtility.UrlEncode(zipFilePath)}/ZipFileName.zip";
}
}
Your users can spam that download "button" as much as they like - the browser will handle parallel downloads.
If you want it to look like a button, that's just a bit of CSS styling.
Notice: The method GetZipURL is just returning a string - it is not redirecting or navigating.
I used target="_new"
to prevent Blazor intercepting the event - but this is not required from .NET5 onwards.
Upvotes: 1