I have this code for creating an Excel file and then sending it for download:
Stream stream = Stream.Null;
using (ExcelDocument doc = ExcelDocument.CreateWorkbook(stream))
{
ExcelWorksheet wsheet = doc.Workbook.Worksheets.Add("Assessment");
doc.EnsureStylesDefined();
// add some cells
}
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "inline;filename=Assessment.xlsx;charset=utf-8;");
Response.BinaryWrite(Utilities.Utilities.ConvertFileToByteArray(stream));
Response.End();
When it gets to end of the using, I get this error :
File contains corrupted data.
If I save file to my disk it works fine.
where I went wrong?
I'm using this Component.
change first line to :
MemoryStream stream = new MemoryStream();
Also Change
Response.BinaryWrite(Utilities.Utilities.ConvertFileToByteArray(stream));
to
Response.BinaryWrite(stream.ToArray());
Related
I want to make a button that makes the download of a DataTable object using an HTTP request.
I already have this code that can print .xls files by changing the contentType as indicated in comment.
However, this does not work with xlsx file.
private void DownloadExcel(DataSet ds, string excelFileNameNowDateTime)
{
System.IO.StringWriter tw = new System.IO.StringWriter(); ;
System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(tw);
System.Web.UI.WebControls.DataGrid dgGrid = new System.Web.UI.WebControls.DataGrid();
dgGrid.DataSource = ds.Tables[0];
// Get the HTML for the control.
dgGrid.HeaderStyle.Font.Bold = false;
dgGrid.DataBind();
dgGrid.RenderControl(hw);
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//string contentType = "application/vnd.ms-excel";
Response.ContentType = contentType;
this.EnableViewState = true;
Response.Clear();
//Response.ContentEncoding = System.Text.Encoding.Default;
Response.AddHeader("content-disposition", String.Format(#"attachment; filename={0}", excelFileNameNowDateTime + ".xlsx"));
Response.Write(tw.ToString());
CloseHTTPResponse();
}
While opening the file is giving me the error
Excel cannot open the file .xlsx because the file format is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.
Any idea on why this does not work?
It looks to me like you're trying to send HTML contents with .xlsx extension. This won't work since XLSX is fundamentally not HTML, but zipped XML with quite specific (and convoluted) schema. The simplest way to achieve your goal would be to use one of the existing 3rd party libraries that can generate XLSX on the fly. I personally had used ClosedXML for a similar task, but there are many other options at NuGet.
This code doesn't produce an Excel file, it produces an HTML file with a fake extension. Excel won't be fooled, it will try to import this HTML file using the user locale's defaults. This will easily lead to problems if the decimal separator is different or the cells contain text that interferes with HTML.
There's no reason for such code. XLSX is a ZIP package containing well-formed XML files. You can use the Open XML SDK to create Excel files at a low level or you can use libraries like EPPlus (57M downloads), ClosedXML (27M), NPOI (22M) and more, to create real Excel files.
With EPPlus, creating an Excel file from a DataTable is really a single command, sheet.Cells.LoadFromDataTable(dt);
public byte[] Export(DataTable dt)
{
using (var p = new ExcelPackage())
{
var ws = p.Workbook.Worksheets.Add("SomeSheet");
var table=ws.Cells.LoadFromDataTable(dt);
var excelData = package.GetAsByteArray();
return excelData;
}
}
After that, you write the output to the Response stream :
var bytes = Export(dt);
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", $"attachment;filename={excelFileNameNowDateTime}.xlsx");
Response.BinaryWrite(bytes);
Response.End();
For ASP.NET (no .NET Core Required solution).
using ClosedXML.Excel;
private void DownloadExcelClosedXML(DataTable dt)
{
using (var workbook = new XLWorkbook())
{
var worksheet = workbook.Worksheets.Add(dt);
using (var stream = new MemoryStream())
{
workbook.SaveAs(stream);
var content = stream.ToArray();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheet.sheet";
Response.AddHeader("content-disposition", "attachment; filename=name_you_file.xlsx");
Response.BinaryWrite(content);
Response.End();
}
}
}
I have PDF document saved into my PDFs folder. I have created one function whose duty is to load the PDF into PdfDocument class, add some styles on runtime, save it back as temporary file and preview it in WebClient. My logic is working absolutely fine. I want to eliminate saving it back as temporary file. I want to directly preview it without saving, is it possible? I searched online but didn't get any good source. Following is my code:
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("MyFile.pdf");
pdf.SaveToFile("ModifiedMyFile.pdf"); // Eliminate this part
WebClient User = new WebClient();
Byte[] FileBuffer = User.DownloadData("ModifiedMyFile.pdf");
if (FileBuffer != null)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", FileBuffer.Length.ToString());
Response.BinaryWrite(FileBuffer);
}
According to spire's documentation, you have two ways to do that
Using SaveToHttpResponse() method
https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/How-to-Create-PDF-Dynamically-and-Send-it-to-Client-Browser-Using-ASP.NET.html
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("MyFile.pdf");
.... edit the document
pdf.SaveToHttpResponse("sample.pdf",this.Response, HttpReadType.Save);
Or, if the built-in method doesn't work, try to use a memory stream instead of a temporary file.
https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/Document-Operation/Save-PDF-file-to-Stream-and-Load-PDF-file-from-Stream-in-C-.NET.html
PdfDocument pdf = new PdfDocument();
.... edit the document
using (MemoryStream ms = new MemoryStream())
{
pdfDocument.SaveToStream(ms);
Byte[] bytes = ms.ToArray();
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", bytes.Length.ToString());
Response.BinaryWrite(bytes);
}
I've searched through most of the 300+ posts on this topic and cannot find one that addresses this issue specifically.
I tried the simplest of file creators with the same result: (from http://www.codeproject.com/Articles/686994/Create-Read-Advance-PDF-Report-using-iTextSharp-in#1) I found this link in another post.
public byte[] generatePublicationCitationReport(List<int> pubIDs)
{
//Step 1: Create a System.IO.FileStream object:
MemoryStream ms = new MemoryStream();
//Step 2: Create a iTextSharp.text.Document object:
Document doc = new Document();
//Step 3: Create a iTextSharp.text.pdf.PdfWriter object. It helps to write the Document to the Specified FileStream:
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
//Step 4: Openning the Document:
doc.Open();
//Step 5: Adding a Paragraph by creating a iTextSharp.text.Paragraph object:
doc.Add(new Paragraph("Hello World"));
//Step 6: Closing the Document:
doc.Close();
return ms.ToArray();
}
The code was modified slightly changing the "filestream" to "memorystream" and passing that back to the calling function to open the file.
The code above generates a 0 byte file and tries to open it. When opening fails, I get an error message indicating "Failed to load PDF file."
I'm trying to generate a PDF file from a list of citations created from data in an SQL database. I'm getting the data properly and can display it using Response.Write.
In my code I add a loop to create each citation individually and add it to the paragraph.
iTextSharp.text.Paragraph paragraph1 = new iTextSharp.text.Paragraph();
iTextSharp.text.Paragraph paraCitations = new iTextSharp.text.Paragraph();
iTextSharp.text.Paragraph paragraph3 = new iTextSharp.text.Paragraph();
iTextSharp.text.Chunk chunk1 = new iTextSharp.text.Chunk("Chunky stuff here...");
paragraph1.Add("Paragraph stuff goes here...");
for (int i = 0; i < pubIDs.Count; i++)
{
string pubCitation = createPubCitation(pubIDs[i]);
chunk1.Append(pubCitation);
paraCitations.Add(chunk1);
}
paragraph3.Add("New paragraph - paraCitations - goes here");
doc.Add(paragraph1);
doc.Add(paraCitations);
doc.Add(paragraph3);
doc.Close();
return ms.toArray();
}
Any suggestions? Pointers? Answer?
Thanks,
Bob
This is the call to and return from the procedure to create the PDF file and open it...
pubCitationAsPDF = p.generatePublicationCitationReport(pubIDs);
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment; filename=publicationCitations.pdf");
Response.End();
Response.Flush();
Response.Clear();
As per comments, it appears your issue is more related to how you download the file, vs creating the file.
Your code for downloading does not include adding the bytes from your memory stream to your response.
Change your download code to this:
Response.Clear();
Response.ContentType = "application/force-download";
Response.AddHeader("content-disposition", "attachment; filename=publicationCitations.pdf");
// This is the piece you're missing
Response.BinaryWrite(p.generatePublicationCitationReport(pubIDs));
Response.End();
I have copied code previously used throughout the system i am working on. However this code opens the content in a word document. I am looking it to be opened in a PDF.
I have already tried changing the string declaration 'filename' to end in (.pdf) as opposed to (.doc) but when attempting to open it it says "could not open the document because it is either not a spported file type or because the file has been damaged....".
What changes need to be made to this code in order to open it as an adope pdf. I wouldnt imagine it would be alot.
string content = sw.GetStringBuilder().ToString();
string fileName = "IRPBestPracticeArticle.doc";
Response.AppendHeader("Content-Type", "application/msword; charset=utf-8");
Response.AppendHeader("Content-disposition", "attachment; filename=" + fileName);
Response.Charset = "utf-8";
Response.Write(content);
I cannot say for certain, but I am going to assume you're trying to save your data as a pdf and have it open in whatever application the system uses to read pdf files?
//Note the change from application/msword to application/pdf
Response.AppendHeader("Content-Type", "application/pdf; charset=utf-8");
Make sure to change the mime type as well as the doc ending (See here for full list of mime types):
That being said, I cant guarantee it will open properly in your PDF reader
Just try this set of code.
Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader("Content-Disposition", "inline;filename=" + fileName);
Response.ContentType = "application/pdf";
Response.WriteFile("FullFilePath");
Response.Flush();
Response.Clear();
Response.End();
The mime type need to be set correctly before opening the file.
Andy try this one. You must have ItextSharp.dll to use this code. Download it from here. Then add its reference in your page.
try this code to create pdf from string and download it
Document document = new Document(PageSize.A4);
using (MemoryStream ms = new MemoryStream())
{
PdfWriter.GetInstance(document, ms);
document.Open();
System.Xml.XmlTextReader _xmlr;
if (String.IsNullOrEmpty(errorMsg))
_xmlr = new System.Xml.XmlTextReader(new StringReader(GetTransferedData(content)));
else
_xmlr = new System.Xml.XmlTextReader(new StringReader(#"<html><body>Error Message:" + errorMsg + "</body></html>"));
iTextSharp.text.html.HtmlParser.Parse(document, _xmlr);
document.Close();
ms.Flush();
byte[] data = ms.ToArray();
Response.Clear();
Response.ClearHeaders();
Response.ClearContent();
Response.Buffer = true;
Response.ContentType = "application/pdf";
Response.BinaryWrite(data);
Response.End();
ms.Close();
}
First, convert the .doc files to PDF files. Here is a sample of how to achieve this: Convert Doc file to PDF in VB.Net
After you have the PDF files, stream them to the browser using the "application/pdf" content type.
I am trying to use the amazing DocX library on codeplex to create a word document.
when the user clicks a button, the document is created and I want to be able to send it to the user immediately via response.. I am doing something similar to this now:
Edited code based on suggestions
using (DocX Report = DocX.Create(string.Format("Report-{0}.doc", DateTime.Now.Ticks)))
{
Paragraph p = Report.InsertParagraph();
p.Append("Title").FontSize(30).Bold()
.Append("Sub title").FontSize(28)
.AppendLine()
.Append(DateTime.Now.Date)
;
MemoryStream ms = new MemoryStream();
Report.SaveAs(ms);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".docx\"");
Response.ContentType = "application/msword";
Response.Write(ms);
Response.End();
}
I have tried a few variations of this.. but I am not able to achieve what I want.. Looking at this answer I can possibly save the document on the server and open with io stream.. but I want to avoid that extra step (and then I need to delete the file too)
I don't see the point of creating a file for few milli seconds.. there has to be a way to save the contents and send them to response stream.. right?
How'd I go about it?
thanks..
EDIT: my current code either throws up cannot open file (Access denied) error If I am using file stream, OR downloads an empty document file without any content (sometimes, type of response is written to document)
This code gets me an MS word document with System.IO.MemoryStream as it's content..
Okay, here is the final working solution:
For some reason, DocX library doesn't want to save to Response.OutputStream directly, so I had to save it to memory stream and write the memory stream to response, like Neil & Daniel suggested. Here's what worked for me:
MemoryStream ms = new MemoryStream()
Report.SaveAs(ms);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".doc\");
Response.ContentType = "application/msword";
ms.WriteTo(Response.OutputStream);
Response.End();
This might be a bit late, but I found a way to get this working with FileStreamResult:
public FileStreamResult DownloadDocument()
{
using (DocX document = DocX.Create(#"Test.docx"))
{
// Insert a new Paragraphs.
Paragraph p = document.InsertParagraph();
p.Append("I am ").Append("bold").Bold()
.Append(" and I am ")
.Append("italic").Italic().Append(".")
.AppendLine("I am ")
.Append("Arial Black")
.Font(new FontFamily("Arial Black"))
.Append(" and I am not.")
.AppendLine("I am ")
.Append("BLUE").Color(Color.Blue)
.Append(" and I am")
.Append("Red").Color(Color.Red).Append(".");
var ms = new MemoryStream();
document.SaveAs(ms);
ms.Position = 0;
var file = new FileStreamResult(ms, "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
{
FileDownloadName = string.Format("test_{0}.docx", DateTime.Now.ToString("ddMMyyyyHHmmss"))
};
return file;
}
}
The important bit is setting the Position of the memorystream back to 0, otherwise it appeared to be at the end, and the file was returning empty.
Try using a MemoryStream instead of a FileStream.
Your current code looks really wrong:
You are saving the report to the OutputStream of the current response and then clear that response (!)
When you do Report.SaveAs(response.OutputStream); - it already writes file contents to the output stream. You don't need to do Response.Write(response.OutputStream);
So you code should look like this:
...
Report.SaveAs(response.OutputStream);
Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".doc\"");
Response.ContentType = "application/msword";
I think you've got things a little back to front and confused.
First off, clear the output, then add the headers, then write out the content.
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=\"" + fileName + ".doc\"");
Response.ContentType = "application/msword";
// This writes the document to the output stream.
Report.SaveAs(response.OutputStream);
Response.End();
Also , if your file is a docx format file, append .docx rather than .doc to your filename.