I'm trying to download a ZIP file in ASP NET MVC. I have done in ASP NET Webforms, and it works correcly, but I do the same in MVC and I don't get the same result, I tried the following:
public ActionResult Download()
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Directories/hello"));
zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
return File(Server.MapPath("~/Directories/hello/sample.zip"),
"application/zip", "sample.zip");
}
}
But I get the binary data in screen, not the downloaded zip file why this is not working in MVC?
I have found that this does not work if I do it from a partial class, if I execute the download code from the Index and send the file if it works, why?
CodePudding user response:
I use this to download files. In your view:
var ext = Path.GetExtension(path);
string contentType = GetMimeType(ext);
using (var stream = fileManager.GetStream(path))
{
var filename = fileManager.GetFileName(path);
var response = System.Web.HttpContext.Current.Response;
TransmitStream(stream, response, path, filename, contentType);
return new EmptyResult();
}
Where GetMimeType
is a method that return known MIME types:
public static string GetMimeType(string extension, string defaultValue = "application/octet-stream")
{
if (extension == null)
{
throw new ArgumentNullException(nameof(extension));
}
if (!extension.StartsWith("."))
{
extension = "." extension;
}
string mime;
return _mappings.TryGetValue(extension, out mime) ? mime : defaultValue;
}
With _mappings
as:
private static readonly IDictionary<string, string> _mappings =
new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) {
{".323", "text/h323"},
{".3g2", "video/3gpp2"},
{".3gp", "video/3gpp"},
{".3gp2", "video/3gpp2"},
{".3gpp", "video/3gpp"},
{".7z", "application/x-7z-compressed"},
// Other types...
{".xwd", "image/x-xwindowdump"},
{".z", "application/x-compress"},
{".zip", "application/x-zip-compressed"},
};
And the TransmitStream
:
public static void TransmitStream(
Stream stream, HttpResponse response, string fullPath, string outFileName = null, string contentType = null)
{
contentType = contentType ?? MimeMapping.GetMimeMapping(fullPath);
byte[] buffer = new byte[10000];
try
{
var dataToRead = stream.Length;
response.Clear();
response.ContentType = contentType;
if (outFileName != null)
{
response.AddHeader("Content-Disposition", "attachment; filename=" outFileName);
}
response.AddHeader("Content-Length", stream.Length.ToString());
while (dataToRead > 0)
{
// Verify that the client is connected.
if (response.IsClientConnected)
{
// Read the data in buffer.
var length = stream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
response.OutputStream.Write(buffer, 0, length);
// Flush the data to the output.
response.Flush();
buffer = new byte[10000];
dataToRead = dataToRead - length;
}
else
{
// Prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
finally
{
response.Close();
}
}
CodePudding user response:
Usually, if you want to download something i suggest you to use ContentResult
,transforming the file you want to download into a Base64 String and transforming it on the frontend using javascript with a Blob
Action
public ContentResult Download()
{
MemoryStream memoryStream = new MemoryStream();
file.SaveAs(memoryStream);
byte[] buffer = memoryStream.ToArray();
string fileAsString = Convert.ToBase64String(buffer);
return Content(file, "application/zip");
}
front end
var blob = new Blob([Base64ToBytes(response)], { type: "application/zip" });
var link = document.createElement("a");
document.body.appendChild(link);
link.setAttribute("type", "hidden");
link.href = url.createObjectURL(blob);
link.download = fileName;
link.click();