ZipOutputStream generates corrupted zip file when zipenty is numerous - c#

I have the code below to simulate an action i am trying to perform using SharpZipLib. The generated zip file runs well when the limit of 'i' is low. But as 'i' tends towards a high value e.g 100, the generated zip file is corrupted. When I repair it, it opens okay. Is there any mistake i am making. Thanks.
using(MemoryStream memoryStream = new MemoryStream())
using (ZipOutputStream zipOutputStream = new ZipOutputStream(memoryStream))
{
zipOutputStream.SetLevel(3);
for (int i = 1; i < 10; i++)
{
ZipEntry zipEntry = new ZipEntry("Test" + i.ToString() + ".xlsx");
zipEntry.DateTime = DateTime.Now;
zipOutputStream.PutNextEntry(zipEntry);
using (Stream inputStream = File.OpenRead(#templatePath))
{
StreamUtils.Copy(inputStream, zipOutputStream,
new byte[inputStream.Length]);
inputStream.Close();
zipOutputStream.CloseEntry();
}
}
zipOutputStream.IsStreamOwner = false;
zipOutputStream.Close();
memoryStream.Position = 0;
WorkbookUtil.StreamFileToBrowser("Report.Zip", memoryStream.GetBuffer());
}
WorkbookUtil.StreamFileToBrowser is my static method to download files to the user browser
Update:
This is the Method for downloading to Browser
public static void StreamFileToBrowser(string sFileName, byte[] fileBytes)
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Response.Clear();
context.Response.ClearHeaders();
context.Response.ClearContent();
context.Response.AppendHeader("content-length", fileBytes.Length.ToString());
context.Response.ContentType = GetMimeTypeByFileName("application/zip");
context.Response.AppendHeader("content-disposition", "attachment; filename=" + sFileName);
context.Response.BinaryWrite(fileBytes);
context.ApplicationInstance.CompleteRequest();
}

Related

exporting to PDF in a loop in crystal reports

I am facing difficulties in generating more than 1 PDF's of Crystal report i-e in a loop. Basically I am creating PDF's then zipping those files and generating HTTP Response.For the sake of demonstration of code i am running loop twice here is my code.
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");
using (ZipFile zip = new ZipFile())
{
for (int i = 0; i < 2; i++)
{
var re = rpt.ExportToStream(ExportFormatType.PortableDocFormat);
string Name="PDF"+i+".pdf";
zip.AddEntry(Name, re);
}
zip.Save(Response.OutputStream);
}
Response.Clear();
It successfully generates the zip file but when i try to extract it i gives an error No archive found (The archive is either in unknown formate or damaged). Any help would be appreciated. Btw I followed this link Export Crystal Report to PDF in a Loop only works with first
Using of memorystreem if zip file not attached to local path.
Response.ClearContent(); Response.ClearHeaders();
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment;
filename=Report.zip");
using (var memoryStream = new MemoryStream()) { using (var
archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
for (int i = 0; i < 2; i++)
{
var re = rpt.ExportToStream(ExportFormatType.PortableDocFormat);
string Name="PDF"+i+".pdf";
zip.AddEntry(Name, re);
zip.Save(memoryStream);
} } }
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.WriteTo(Response.OutputStream);

Unable to download Excel file when call from Postman

I am trying to download Excel file using web API but I am unable to download file in postman where as I am able to download Excel file when I enter URL in browser though while opening file I get warning message like below :
When i hit endpoint using POSTMAN then file get corrupted and it is showing junk characters.
Code :
protected virtual byte[] ExportToXlsx<T>(IEnumerable<T> itemsToExport)
{
using (var stream = new MemoryStream())
{
using (var xlPackage = new ExcelPackage())
{
// get handles to the worksheets
var worksheet = xlPackage.Workbook.Worksheets.Add(typeof(T).Name);
//create Headers and format them
var manager = new PropertyManager<T>(itemsToExport.First());
manager.WriteCaption(worksheet, SetCaptionStyle);
var row = 2;
foreach (var items in itemsToExport)
{
manager.CurrentObject = items;
manager.WriteToXlsx(worksheet, row++, false);
}
xlPackage.Save();
}
return stream.ToArray();
}
}
private readonly IServiceContext ctx;
public void Download(string guid)
{
var bytes = ExportToXlsx(list);
ctx.reqobj.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=\"demo.xlsx\"");
ctx.reqobj.HttpContext.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
ctx.reqobj.HttpContext.Response.Body.Write(bytes, 0, bytes.Length);
}
Note : I am using OfficeOpenXml for Excel file creation.
I will appreciate any help.
Update :
Try using "Send and download" instead of "Send"
https://www.getpostman.com/docs/v6/postman/sending_api_requests/responses
Postman doesn't download any file just return you the data that the server or your service provides. i have a project that download an excel to with the OpenXML here is an example with which you can guide with some styles to.
[HttpGet]
public void DownloadTable(int id)
{
List<Employee> all = db.Employees.Where(x => x.ManagerId == id).ToList();
String file = "Example.xlsx";
String path = Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data"), file);
List<string[]> headerRow = new List<string[]>() { new string[] { "EmployeeId", "Name", "Shift", "Timestamp" } };
string headerRange = "A2:" + Char.ConvertFromUtf32(headerRow[0].Length + 64) + "2";
ExcelPackage excel = new ExcelPackage();
excel.Workbook.Worksheets.Add("Employees");
var page = excel.Workbook.Worksheets["Employees"];
page.Cells["A1:D1"].Merge = true;
page.Cells["A1:D1"].Value = "Supervisor: " + all.FirstOrDefault().Manager + " - " + id;
page.Cells["A1:D1"].Style.Font.Bold = true;
page.Cells[headerRange].LoadFromArrays(headerRow);
int z = 3;
foreach (Reporte r in all)
{
page.Cells["A" + z].Value = r.Id;
page.Cells["B" + z].Value = r.Name;
page.Cells["C" + z].Value = r.Shift;
page.Cells["D" + z].Value = r.Timestamp;
z++;
}
page.Cells["D3:D" + z].Style.Numberformat.Format = "dddd dd MMMM YYYY";
page.Cells["A2:D2"].AutoFilter = true;
page.Cells["A1:D" + z].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
page.Cells["A1:D" + z].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
page.Cells["A2:D" + z].AutoFitColumns();
page.Cells["A1:D1"].Style.Fill.PatternType = ExcelFillStyle.Solid;
page.Cells["A1:D1"].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(1, 183, 222, 232));
FileInfo excelFile = new FileInfo(path);
excel.SaveAs(excelFile);
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "text/plain";
response.AddHeader("Content-Disposition",
"attachment; filename=" + file + ";");
response.TransmitFile(path);
response.Flush();
response.End();
File.Delete(path);
}
The stream needs to be passed to the package.
Right now nothing is being given to the package,
//...
using (var xlPackage = new ExcelPackage())
//...
So nothing is being saved to the stream, which is why the error is shown when trying to open the file.
There is no need to convert the memory stream to an array. Return the stream and pass that along for the response.
protected virtual Stream ExportToXlsx<T>(IEnumerable<T> itemsToExport) {
var stream = new MemoryStream();
using (var xlPackage = new ExcelPackage(stream)) { //<<< pass stream
// get handles to the worksheets
var worksheet = xlPackage.Workbook.Worksheets.Add(typeof(T).Name);
//create Headers and format them
var manager = new PropertyManager<T>(itemsToExport.First());
manager.WriteCaption(worksheet, SetCaptionStyle);
var row = 2;
foreach (var items in itemsToExport) {
manager.CurrentObject = items;
manager.WriteToXlsx(worksheet, row++, false);
}
xlPackage.Save();
}
return stream;
}
A controller action to return the file would look like this
public IActionResult Download(string guid) {
//...get list
var file = ExportToXlsx(list);
var contentType = "application/vnd.openxmlformats";
var fileName = "demo.xlsx";
return File(file, contentType, fileName); //returns a FileStreamResult
}
It was indicated in comments that the above is done in a support method.
Using the same approach
private readonly IServiceContext ctx;
//...
public void Download(string guid) {
//...get list
using(var fileStream = ExportToXlsx(list)) {
if (fileStream.CanSeek && fileStream.Position != 0) {
fileStream.Seek(0, SeekOrigin.Begin);
}
var contentType = "application/vnd.openxmlformats";
var fileName = "demo.xlsx";
var response = ctx.reqobj.HttpContext.Response;
response.Headers.Add("Content-Disposition", $"attachment; filename=\"{fileName}\"");
response.Headers.Add("Content-Length", fileStream.Length.ToString());
response.ContentType = contentType;
fileStream.CopyTo(response.Body);
}
}
the generated file is copied over to the body of the response.
As for postman, the tool is simply showing the content return in the response. It does not try to download the actual file as an attachment.

How to convert a byte array to pdf

I am building an app that modifies a word 2010 document and it should be downloaded as pdf.I write a code to convert word to pdf but it is converting the document I upload not the modified word. How can I convert modified word to PDF.Below is the function which is not converting modified word.
protected void btnUpload_Click(object sender, EventArgs e)
{
if (FileUploadControl.HasFile)
{
string fileNameFromUser = FileUploadControl.FileName;
var fiFileName = new System.IO.FileInfo(fileNameFromUser);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(FileUploadControl.FileBytes, 0, FileUploadControl.FileBytes.Length);
using (WordprocessingDocument sDoc = WordprocessingDocument.Open(ms, true))
{
}
lblMessage.Text = "Dokumenti u ngarkua me sukses!";
Session["ByteArray"] = FileUploadControl.FileBytes;
Session["fileNameFromUser"] = fileNameFromUser;
}
}
byte[] byteArray = (byte[])(Session["ByteArray"]);
if (byteArray != null)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
{
var body = wDoc.MainDocumentPart.Document.Body;
var lastParagraf = body.Elements<Paragraph>().LastOrDefault();
var newParagraf = new Paragraph(
new Run(
new Text("Perdoruesi:" + " " + User.Identity.Name)));
var newParagraf2 = new Paragraph(
new Run(
new Text("Data dhe ora:" + " " + DateTime.Now.ToString())));
var newParagraf3 = new Paragraph(
new Run(
new Text("Kodi unik:" + " " + randomstring(14))));
var newParagraf4 = new Paragraph(
new Run(
new Text("Shifra:" )));
lastParagraf.InsertAfterSelf(newParagraf);
lastParagraf.InsertAfterSelf(newParagraf2);
lastParagraf.InsertAfterSelf(newParagraf3);
lastParagraf.InsertAfterSelf(newParagraf4);
}
Session["ByteArray"] = ms.ToArray();
lblMessage.Text = "U ngarkua dhe u vulos dokumenti!";
Guid pdfFileGuid = Guid.NewGuid();
var filePath = Path.GetTempFileName();
FileUploadControl.SaveAs(filePath);
var appWord = new Microsoft.Office.Interop.Word.Application();
var wordDoc = appWord.Documents.Open(filePath);
var convertedFilePath = Path.GetTempFileName();
wordDoc.ExportAsFixedFormat(convertedFilePath, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=Converted.Pdf");
Response.AddHeader("content-type", "application/pdf");
Response.TransmitFile(convertedFilePath);
File.Delete(filePath);
File.Delete(convertedFilePath);
}
}
catch (Exception ex)
{
lblMessage.Text = "ERROR:" + ex.Message.ToString();
}
}
else
{
lblMessage.Text = "Nuk e keni zgjedhur dokumentin apo formati i dokumentit nuk pershtatet!";
}
}
Currently, here you load the data from the FileUploadControl into session:
Session["ByteArray"] = FileUploadControl.FileBytes;
You then load the data from session into a MemoryStream that you use to open the document for editing:
byte[] byteArray = (byte[])(Session["ByteArray"]);
if (byteArray != null)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
At the end of this, after your edits, you copy the updated content back to session:
lastParagraf.InsertAfterSelf(newParagraf3);
lastParagraf.InsertAfterSelf(newParagraf4);
}
Session["ByteArray"] = ms.ToArray();
but; that's the last time we see session used; you then write the uploaded file to a temporary file, and use that to perform Word automation:
var filePath = Path.GetTempFileName();
FileUploadControl.SaveAs(filePath);
var appWord = new Microsoft.Office.Interop.Word.Application();
var wordDoc = appWord.Documents.Open(filePath);
So yes: this will convert the original file as uploaded, because FileUploadControl is unrelated to the changes you made. Instead, perhaps try:
var filePath = Path.GetTempFileName();
File.WriteAllBytes(filePath, (byte[])Session["ByteArray"]);
var appWord = new Microsoft.Office.Interop.Word.Application();
var wordDoc = appWord.Documents.Open(filePath);
This should then include the changes.
Additional side observations:
Word automation is unsupported and not recommended on web-servers; if it works for you: great, but just be aware that if it suddenly breaks you'll be on your own
be careful that you're not leaving files scattered on disk, or lots of open Word instances / files; basically: check you're not "leaking" (appWord, wordDoc, filePath, convertedFilePath etc - all probably need some finally love)
putting Word files into session-state (Session) probably isn't a good or necessary idea; I would recommend just using a local byte[] or similar throughout in this method, and remove Session["ByteArray"] completely

Unable to get full image from server

I have a C# windows form application which downloads file from a url(asp.net application) but it is not returning full image lets say image is of 780kb the file that windows form creates is 381 bytes exactly.
I am not able to figure out the issue. Please help.
The code i am using for download is:
public bool getFileFromURL(string url, string filename)
{
long contentLength = 0;
Stream stream = null;
try
{
WebRequest req = WebRequest.Create(url);
WebResponse response = req.GetResponse();
stream = response.GetResponseStream();
contentLength = response.ContentLength;
// Transfer the file
byte[] buffer = new byte[10 * 1024]; // 50KB at a time
int numBytesRead = 0;
long totalBytesRead = 0;
using (FileStream fileStream = new FileStream(filename, FileMode.Create))
{
using (BinaryWriter fileWriter = new BinaryWriter(fileStream))
{
while (stream.CanRead)
{
numBytesRead = stream.Read(buffer, 0, buffer.Length);
if (numBytesRead == 0) break;
totalBytesRead += numBytesRead;
fileWriter.Write(buffer, 0, numBytesRead);
}
fileWriter.Close();
}
fileStream.Close();
}
stream.Close();
response.Close();
req.Abort();
return true;
}
catch (Exception)
{
return false;
}
}
This is my asp.net app code:
using (PortalEntities db = new PortalEntities())
{
PortalModel.Command command = db.Commands.SingleOrDefault(c => c.id == id);
var filePath = Server.MapPath("~/Uploads/"+command.arguments);
if (!File.Exists(filePath))
return;
var fileInfo = new System.IO.FileInfo(filePath);
Response.ContentType = "image/jpg";
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath));
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
Response.WriteFile(filePath);
Response.End();
}
That's an awful lot of code to write some bytes out to a file from a web response. How about something like this (.NET 4+):
public static bool GetFileFromURL(string url, string filename)
{
try
{
var req = WebRequest.Create(url);
using (Stream output = File.OpenWrite(filename))
using (WebResponse res = req.GetResponse())
using (Stream s = res.GetResponseStream())
s.CopyTo(output);
return true;
}
catch
{
return false;
}
}
You can download image in more elegant way, it was discussed before here Unable to locate FromStream in Image class
And use File.WriteAllBytes Method to save the byte array as a file, more info at
http://msdn.microsoft.com/en-us/library/system.io.file.writeallbytes(v=vs.110).aspx
So all your client code can be replaced with
public void getFileFromURL(string url, string filename)
{
using (var webClient = new WebClient())
{
File.WriteAllBytes(filename,webClient.DownloadData(url));
}
}
Dude, why are you not using WebClient.DownloadFileAsync?
private void DownloadFile(string url, string path)
{
using (var client = new System.Net.WebClient())
{
client.DownloadFileAsync(new Uri(url), path);
}
}
That's pretty much it, but this method can't download over 2GB. But i don't think the image is that big xD.
Hope it helps!

c# - DotNetZip open zip file from MemoryStream

What I like to do is instead of storing a zip file on disk, I like to open it up from a MemoryStream.
I am looking at the documentation for DotNetZip programming example:
Note that I tweaked it slightly based on what I thought may be needed.
var ms = new MemoryStream();
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(ms); // this will save the files in memory steam
}
// now what I need is for the zip file to open up so that
the user can view all the files in it. Not sure what to do next after
zip.Save(ms) for this to happen.
Try this:
public ActionResult Index()
{
var memoryStream = new MemoryStream();
using (var zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(memoryStream);
}
memoryStream.Seek(0, 0);
return File(memoryStream, "application/octet-stream", "archive.zip");
}
If this is local. you will need to save the stream in to the file and call Process.Start on it.
If this is on server. Just write your ms into Response with appropriate mime type.
You'd have to send the content of the memory stream back as the response:
using (MemoryStream ms = new MemoryStream())
{
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(ms); // this will save the files in memory steam
}
context.Response.ContentType = "application/zip";
context.Response.AddHeader("Content-Length", ms.Size);
context.Response.AddHeader("Content-disposition", "attachment; filename=MyZipFile.zip");
ms.Seek(0, SeekOrigin.Begin);
ms.WriteTo(context.Response.OutputStream);
}
Try creating an ActionResult a bit like this:
I'm not 100% sure about the line var fileData = ms; and i don't have access to a dev environment just now, but there should be enough for you to work it out.
public ActionResult DownloadZip()
{
using (MemoryStream ms = new MemoryStream())
{
using (ZipFile zip = new ZipFile())
{
zip.AddFile("ReadMe.txt");
zip.AddFile("7440-N49th.png");
zip.AddFile("2008_Annual_Report.pdf");
zip.Save(ms); // this will save the files in memory steam
}
byte[] fileData = ms.GetBuffer();// I think this will work. Last time I did it, I did something like this instead... Zip.CreateZip("LogPosts.csv", System.Text.Encoding.UTF8.GetBytes(csv));
var cd = new System.Net.Mime.ContentDisposition
{
FileName = "Whatever.zip",
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(fileData, "application/octet-stream");
}
}
this way we can write zip to output stream. may help
ZipFile zip = new ZipFile();
List<Attachment> listattachments = email.Attachments;
int acount = attachments.Count;
for (int i = 0; i < acount; i++)
{
zip.AddEntry(attachments[i].FileName, listattachments[i].Content);
}
Response.Clear();
Response.BufferOutput = false;
string zipName = String.Format("{0}.zip", message.Headers.From.DisplayName);
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=" + zipName);
zip.Save(Response.OutputStream);
Response.End();

Categories