'.net MVC How do I download a file and stay on the same page?
I am developing a page where a user can download a .zip containing a number of .pdf files. The functionality handling the download and the compressing works fine, my issue is that when I press the download button, it puts my page into an endless loop. It is as if it is loading the next View, but since the ActionResult returns a File, not a View or a redirect, it will never get to load a page. I have tried to set the formtarget to _blank, so that the download opens in a new tab, but that still puts the original tab in an endless loop.
Here is my controller method:
[HttpPost]
public ActionResult DownloadCertificatesByModel([Bind(Include = "OrderNumber,ChosenLanguages,ChosenTemplates")] OrderViewModel viewModel)
{
var certificates = GetCertificatesByOrderNumber(viewModel.OrderNumber, viewModel.ChosenLanguages, viewModel.ChosenTemplates);
using (var memoryStream = new MemoryStream())
{
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach(var cert in certificates)
{
//If the file actually exists
if (cert.Value)
{
zipArchive.CreateEntry(cert.Key.CertificateName);
}
}
}
return File(memoryStream.ToArray(), "application/zip", viewModel.OrderNumber + "_certificates.zip");
}
}
Here is the part of my Razor View in question:
<input type="submit" value="Download All Certificates" class="btn btn-default" formaction="DownloadCertificatesByModel" style="margin-right:10px" formtarget="_blank" />
How can I have a controller action that returns a file but keeps the current page as it is, meaning no redirecting or anything, just initiating a download?
UPDATE:
I should mention that the two "Chosen" variables from the model are List<SelectListItem> which means that when I try to follow @cacalonga's suggestion (change POST to GET), I get an error that the query string exceeds the max allowed length. To solve this I have tried to increase the MaxQueryLength in the Web.config, but this does not work either as the query is extremely long as it contains all the SelectListItems.
Solution 1:[1]
You should use httpget method.
[HttpGet]
public ActionResult DownloadCertificatesByModel([Bind(Include = "OrderNumber,ChosenLanguages,ChosenTemplates")] OrderViewModel viewModel)
{
var certificates = GetCertificatesByOrderNumber(viewModel.OrderNumber, viewModel.ChosenLanguages, viewModel.ChosenTemplates);
using (var memoryStream = new MemoryStream())
{
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach(var cert in certificates)
{
//If the file actually exists
if (cert.Value)
{
zipArchive.CreateEntry(cert.Key.CertificateName);
}
}
}
return File(memoryStream.ToArray(), "application/zip", viewModel.OrderNumber + "_certificates.zip");
}
}
On cshtml side:
<form action="/YourActionController/DownloadCertificatesByModel" method="get">
<input type="text" name="OrderNumber" value="" />
<input type="text" name="ChosenLanguages" value="" />
<input type="text" name="ChosenTemplates" value="" />
<input type="submit" value="Download All Certificates" class="btn btn-default" />
/form>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
