ZipArchive creates invalid zip file in list from webservices - c#

I have a problem with get files to zip.
The web service is giving me the right files, for example www.XYP.com/GetFile?=1234 , when I open the Url, automaticly downloads the file, but after I zip this document its not correct files, which are destroyes
My code is here:
private void CreatedZipFile(Dictionary<int, string> listChecked)
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach (KeyValuePair<int, string> kvp in listChecked)
{
ZipArchiveEntry demoFile = archive.CreateEntry(kvp.Key.ToString() + kvp.Value.ToString() + ".pdf");
string strDownLoad = System.Configuration.ConfigurationManager.AppSettings["GETFILESERVICES"] + kvp.Key.ToString();
WebService control = new WebService();
var clientnew = new System.Net.WebClient().DownloadData(strDownLoad);
using (var entryStream = demoFile.Open())
{
using (StreamWriter streamWriter = new StreamWriter(entryStream))
{
streamWriter.BaseStream.Write(clientnew, 0, clientnew.Length);
streamWriter.Close();
}
}
}
}
byte[] bytesInStream = memoryStream.ToArray();
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=file.zip");
Response.Buffer = true;
Response.Clear();
Response.BinaryWrite(bytesInStream);
Response.Flush();
//MemoryStream.WriteTo(Response.OutputStream); //works too
Response.End();
}
}
Thanks for help or any advice,

Related

Returning ZipFile in Controller after reading bytes from database

I'm trying to read files from my database (varbinary) and add them to a zip file so that users can download all files related to a specific user.
From what I can gather, I need to read the files from the database, create the zip file, read the files into memory and then write that to the file (doing it without this returned a blank zip file).
It will save the files to the zip, but unfortunately the files are all corrupted.
public FileResult DownloadAllDocuments(int userId)
{
// File name
string ZipFilename = DateTime.Now + "_Files.zip";
// Get files from database
List<DocumentVO> Documents = DocumentDAO.DownloadAllDocuments(userId);
var zipFileMemoryStream = new MemoryStream();
using (ZipArchive archive = new ZipArchive(zipFileMemoryStream, ZipArchiveMode.Update, leaveOpen: true))
{
foreach (DocumentVO document in Documents)
{
var entry = archive.CreateEntry(document.fileName, CompressionLevel.Fastest);
using (var entryStream = entry.Open())
{
entryStream.Write(document.File, 0, document.File.Length);
}
}
}
zipFileMemoryStream.Seek(0, SeekOrigin.Begin);
return File(zipFileMemoryStream, "application/octet-stream", ZipFilename);
}
Please try these codes instead of return File line
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
Response.ClearHeaders();
Response.ClearContent();
Response.Charset = "";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + ZipFilename);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/zip";
Response.BinaryWrite(ms.ToArray());
}

ZipArchive Produces empty ZIP file

I am trying to create a ZipArchive in memory and append several entries with binary data from database. The problem is that after loop, zip sent to client is invalid/empty. Can you please check my code?
using (MemoryStream _memory_stream = new MemoryStream())
{
using (ZipArchive _archive = new ZipArchive(_memory_stream, ZipArchiveMode.Create, true))
{
foreach (byte[] binaryData in this.FileBinaries)
{
ZipArchiveEntry _entry = _archive.CreateEntry(str_filename, CompressionLevel.Optimal);
using (Stream _entryStream = _entry.Open())
{
using (StreamWriter _writer = new StreamWriter(_entryStream))
{
_writer.Write(binaryData);
}
_entryStream.Close();
}
}
}
Response.AppendHeader("content-disposition", "attachment; filename=certificates.zip");
Response.ContentType = "application/zip";
Response.Write(_memory_stream);
}

Create text files, compress them to a ZipArchive and present it for download

my scenario:
asp.net mvc web application
User clicks on a button in a view to start the action
Action:
Create several csv files from records that are stored in tables of an sql db
Compress all created files into a single ZipArchive
Present the ZipArchive for download to the client computer
I have a working code for creating a single csv file and presenting it for download.
public class ExportCSVController : BaseController
{
public ExportCSVController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
public void ExportCSV_Company()
{
var sb = new StringBuilder();
var companies = UnitOfWork.GetAll<Company>();
var list = companies.ToList();
sb.AppendFormat("{0};{1};{2}{3};{4}", "Name", "Street", "City", "Zipcode", Environment.NewLine);
foreach (var item in list)
{
sb.AppendFormat("{0};{1};{2};{3};{4}", "\"" + item.Name + "\"", item.Street, item.City, item.Zip, Environment.NewLine);
}
//Get Current Response
var response = System.Web.HttpContext.Current.Response;
response.BufferOutput = true;
response.Clear();
response.ClearHeaders();
response.ContentEncoding = Encoding.Unicode;
response.AddHeader("content-disposition", "attachment;filename=Companies.txt ");
response.ContentType = "text/plain";
response.Write(sb.ToString());
response.End();
}
}
I also have a working code for compressing a file to a ZipArchive (using System.IO.Compression).
My idea:
Set up a loop (in my working code) for each file that needs to be generated
after generating the first file, add the file to the ZipArchive (using System.IO.Compression)
continue with the next file generation and append the file to the ZipArchive ...
then present the ZipArchive for download
My problem:
I do not quite understand where in the given code the file is generated, if at all?
I think, that response.Write() just directs the generated string to the browser where finally it is converted to a file when the user clicks on save.
Questions:
Must the response be saved to a file before it can be added to a ZipArchive?
If yes,
How would I convert the response via code to a file?
Is there any way to skip writing a physical file in order to get it into the ZipArchive?
Below, my example solution (for zipping 2 files)
public void ExportFilesToZip()
{
string zipFileName = "Test.zip";
string firstFileName = "FirstFile.txt";
string secondFileName = "SecondFile.txt";
string firstFileContent ="1";
string secondFileContent ="2";
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader("content-disposition", "attachment;filename=" + zipFileName);
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var demoFile = archive.CreateEntry(firstFileName);
using (var entryStream = demoFile.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(firstFileContent);
}
demoFile = archive.CreateEntry(secondFileName);
using (var entryStream = demoFile.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(secondFileContent);
}
}
using (var fileStream = Response.OutputStream)
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
Response.End();
}

Create ZipArchive in memory then download to client

I have read several blog posts and questions about this, but I can't get this working. It just downloads a corrupt ZIP archive that is <2KB. I feel like I'm missing something simple with streaming the PDF file to the Zip Archive?
using (var outStream = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
foreach (string Item in Items)
{
ReportParameter[] prms = new ReportParameter[1];
prms[0] = new ReportParameter("Item", Item, false);
rv.ServerReport.SetParameters(prms);
rv.ShowParameterPrompts = false;
rv.ServerReport.Refresh();
byte[] bytes = rv.ServerReport.Render("PDF", null, out mimeType, out encoding, out extension, out streamids, out warnings);
string fileName = Item + ".pdf";
var fileInArchive = archive.CreateEntry(fileName);
using (var entryStream = fileInArchive.Open())
using (var fileToCompressStream = new MemoryStream(bytes))
{
fileToCompressStream.CopyTo(entryStream);
}
}
}
outStream.Position = 0;
Response.ClearContent();
Response.ClearHeaders();
Response.AppendHeader("content-disposition", "attachment; filename=PDFReports_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".zip");
Response.Write(outStream);
}

C# No Data in Folder after Downloading ASP

Let me start off by saying I'm sure this is something that's quite simple, unfortunately I just can't seem to figure it out. So here's my problem, I query the database, return what I need, zip it all up, and prompt user to save. When You attempt to open this, there are no files inside the folder. Where has my data gone? I stepped through everything, and it appears to write everything properly. Any help would be greatly appreciated!!
if (e.CommandName == "DownloadAttachment")
{
e.Canceled = true;
// Create a zip and send it to the client.
//Response.Write(#"<script language='javascript'>alert('Details saved successfully')</script>");
var item = e.Item as GridEditableItem;
fileId = (int)item.GetDataKeyValue("Unique");
FileData[] allrecords = null;
using (
SqlConnection conn =
new SqlConnection(ConfigurationManager.ConnectionStrings["PtcDbModelEntities"].ConnectionString))
{
using (
SqlCommand comm = new SqlCommand("Select Unique1, BinaryData, FileName from PtcDbTracker.dbo.CafFileTable where Unique1=#fileId AND FileName IS NOT NULL", conn))
{
comm.Parameters.Add(new SqlParameter("#fileId", fileId));
conn.Open();
using (var reader = comm.ExecuteReader())
{
var list = new List<FileData>();
while (reader.Read())
{
list.Add(new FileData { Unique1 = reader.GetInt32(0) });
long len = reader.GetBytes(1, 0, null, 0, 0);
Byte[] buffer = new byte[len];
list.Add(new FileData { BinaryData = (byte)reader.GetBytes(1, 0, buffer, 0, (int)len), FileName = reader.GetString(2) });
allrecords = list.ToArray();
}
}
conn.Close();
}
}
using (var compressedFileStream = new MemoryStream())
{
//Create an archive and store the stream in memory.
using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false))
{
if (allrecords != null)
{
foreach (var record in allrecords)
{
//Create a zip entry for each attachment
if (record.FileName != null)
{
var zipEntry = zipArchive.CreateEntry(record.FileName);
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(record.BinaryData))
{
using (var zipEntryStream = zipEntry.Open())
{
//Copy the attachment stream to the zip entry stream
originalFileStream.CopyTo(zipEntryStream);
}
}
}
}
}
Response.ClearContent();
Response.ClearHeaders();
Response.BinaryWrite(compressedFileStream.ToArray());
Response.AppendHeader("Content-Disposition", "Attachment; filename=result.zip");
Response.Flush();
Response.Close();
zipArchive.Dispose();
//How Do I Prompt for open or save?
}
}
Are you sure the BinaryWrite is getting a valid ByteArray?
In any case here's a tested method to output a file to the Response with the typically needed headers for binary attachments:
public bool WriteFile(byte[] byteContent, DateTime dtTimeStamp, string urlFilename)
{
HttpContext context = HttpContext.Current;
HttpResponse response = context.Response;
response.Clear();
response.ClearHeaders();
response.ClearContent();
response.BufferOutput = true;
response.AppendHeader("Content-Length", byteContent.Length.ToString());
response.AppendHeader("Content-Type", "application/octet-stream");
response.AppendHeader("Last-Modified", dtTimeStamp.ToString("R"));//Last-Modified Wed, 28 Aug 2013 10:16:46 GMT
response.AppendHeader("Content-Disposition", "inline; filename=\"" + urlFilename + "\"");
response.BinaryWrite(byteContent);
response.Flush();
// Prevents any other content from being sent to the browser
response.SuppressContent = true;
context.ApplicationInstance.CompleteRequest();
return true;
}

Categories

Resources