Streaming files and character sets problem - c#

I have made some code which exports some details of a journal article to a reference manager called Endnote
The format of which is a list of items like below (an author):
%A Schortgen Frédérique
Unfortunately, I am having some encoding problems somewhere, as when endnote opens the file, this is what it makes of the above author:
Schortge Frédérique
I have frantically tried playing around with the encoding and stuff that I am outputting and I am at a loss, here is the code:
Response.ContentType = _citation.ContentType;
string fileExtension = "";
if (_citation.GetFileExtension() != null)
fileExtension = "." + _citation.GetFileExtension();
Response.AddHeader("content-disposition", "attachment; filename=citation" + fileExtension);
Response.ContentType = _citation.GetFileReferrer();
Response.Charset = "UTF-8";
Response.write(-snip-);
Response.End();

It looks like Endnote isn't expecting UTF-8. Do you have details of what Endnote does expect? You may find that using Encoding.GetEncoding(1252) or Encoding.GetEncoding(28591) (which are Western codepage 1252 and ISO-8859-1 respectively) might work.
Btw, you're setting Response.ContentType twice. That sounds unlikely to be a good thing.

Response.Charset = "ISO-8859-1";
Response.ContentEncoding = System.Text.Encoding.GetEncoding(28591);
Response.HeaderEncoding = System.Text.Encoding.GetEncoding(28591);
You Sir, are a legend (once again)

Related

Corrupt Excel file output using EPPlus in ASP.NET / C#

I'm trying to use EPPlus to create a report inside an ASP.NET application. I tried using the code provided into samples package but I'm having some troubles.
The following code is executed without error:
ExcelPackage pck = new ExcelPackage();
var ws = pck.Workbook.Worksheets.Add("Sample1");
_ws.Cells["A1"].Value = "COD. CONV.";
_ws.Cells["A1"].Style.Font.Bold = true;
_ws.Cells["A1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
_ws.Cells["B1"].Value = "RAGIONE SOCIALE";
_ws.Cells["B1"].Style.Font.Bold = true;
_ws.Cells["B1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
_ws.Cells["C1"].Value = "COMMERCIALE A";
_ws.Cells["C1"].Style.Font.Bold = true;
_ws.Cells["C1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
_ws.Cells["D1"].Value = "PROVINCIA";
_ws.Cells["D1"].Style.Font.Bold = true;
_ws.Cells["D1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
_ws.Cells["E1"].Value = "ZONA";
_ws.Cells["E1"].Style.Font.Bold = true;
_ws.Cells["E1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
_ws.Cells["F1"].Value = "TELEFONO";
_ws.Cells["F1"].Style.Font.Bold = true;
_ws.Cells["F1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
_ws.Cells["G1"].Value = "EMAIL";
_ws.Cells["G1"].Style.Font.Bold = true;
_ws.Cells["G1"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thick;
int _i = 2;
foreach (DataRow _drRow in dtAnagrafiche.Rows)
{
_ws.Cells["A"+_i.ToString()].Value = _drRow["codice"].ToString();
_ws.Cells["B"+_i.ToString()].Value = _drRow["Nome"].ToString();
_ws.Cells["C"+_i.ToString()].Value = "";
_ws.Cells["D"+_i.ToString()].Value = _drRow["Provincia"].ToString();
_ws.Cells["E"+_i.ToString()].Value = _drRow["Zona"].ToString();
_ws.Cells["F"+_i.ToString()].Value = _drRow["Telefono"].ToString();
_ws.Cells["G"+_i.ToString()].Value = _drRow["Email"].ToString();
_i++;
}
Response.BinaryWrite(_pck.GetAsByteArray());
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=Lista_Anagrafiche.xlsx");
but the resulting file cannot be opened by Microsoft office if not 'recovered', other MS Office compatibile applications (i.e. OpenOffice) cannot open the file.
I can provide the output file if needed.
https://drive.google.com/file/d/0B-lPXYt7laDrbUFKbFZEWEwxckk/view?usp=sharing
BTW I'm using the last (4.0.5) EPPlus package obtained trough nuget, and running it in ASP.NET 4.5 web appplication.
You're missing a call to Response.End(). Without this, you're sending the response with the binary payload (the .xlsx file), which is coming over correctly, then the .aspx page that you're coding this under is being sent in the payload as well. Proof here as shown in a hex editor.
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=Lista_Anagrafiche.xlsx");
Response.BinaryWrite(_pck.GetAsByteArray());
Response.End();
Should do the trick.
As an aside, I would suggest saving the file, then doing a Response.Redirect() to the URL of the file, instead, but that's unrelated to this specific issue.
EDIT: Notably, in normal circumstances, I would suggest avoiding Response.End(), but, that is the quickest way to solve the problem you've coded yourself into. I would suggest looking for better ways to serve up these files in general, as per my above suggestion to Response.Redirect() to a saved location of the file.
Try changing your code to the following notice how I am using the string.Format function to create the filename + extension
you need to declare a constant fileName. if worse comes to worse change the .xlsx to .xls
Response.Clear();
Response.ClearHeaders();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}.xlsx", fileName));
Response.BinaryWrite(_pck.GetAsByteArray());
Response.Flush();
Response.End();

mp3 files not getting downloaded?

I have written the below lines of code in c#
private void DownloadFile(byte[] myData, string Name)
{
Response.Expires = 0;
Response.Clear();
string ext= System.IO.Path.GetExtension(Name);
switch(ext)
{
case ".mp3":
Response.ContentType = "audio/mpeg";
break;
default:
Response.ContentType = "Application/octet-stream";
break;
}
Response.AddHeader("content-length", myData.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + Name);
try
{
Response.BinaryWrite(myData);
}
catch { }
Response.Flush();
Response.End();
}
Now the issue is that whenever we click mp3 file to download, it's directly played. I want that it should download it. Also I want that all types of files should be downloaded.
I struggled with this for the longest time, but finally solved the puzzle. Use Response.WriteFile. You could follow it with Response.Flush but I found that to be unnecessary. Extra headers were not necessary with .mp3 files. In my case, the .mp3 files were in a folder directly under the root. And here's a bonus: The key ingredients for making the .mp3 download work with smartphones (which was my dilemma) were using Response.End, and telling the mobile device that the download was done by sending back the Response.StatusCode = 200.
string FilenameMP3 = "~/someFolder/xyz.mp3";
string headerFilename = Filename.Substring(Filename.IndexOf("/") + 1);
Response.AppendHeader("Content-Disposition", String.Concat("attachment;filename=\"", headerFilename, "\""));
Response.ContentType = "audio/mpeg";
try
{
Response.WriteFile(Filename, true);
Response.End();
}
finally
{
Response.StatusCode = 200;
Response.Close();
}
What you have should be sufficient, assuming that the headers you added aren't being stripped / corrupted in transit (simple to check via Fiddler or similar).
Since you don't want the browser to interpret this data, a pragmatic option might be to simply send all data as "application/octet-stream", regardless of the content. While the "attachment" disposition should be sufficient for this, this approach is explicitly called out in RFC 2616, 19.5.1 ("Content-Disposition"):
If this header is used in a response with the application/octet- stream content-type, the implied suggestion is that the user agent should not display the response, but directly enter a `save response as...' dialog.

Opening a document in PDF as opposed to Word with code on a button click

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.

Why the filename header is incomplete if this has space in ASP.NET MVC 3?

I met today an issue, it is strange for me but, maybe, not for experts in C# field.
I have a function called Download like this ( a piece of code !)
public void Download (string path){
HttpContext.Current.Response.ContentType = "application/octet-stream";
try {
....//process a 'filePath' variable using the 'path' parameter
using ( FileStream sourceFile = new FileStream( filePath, FileMode.Open ) ) {
...
HttpContext.Current.Response.AddHeader( "Content-Disposition", "attachment; filename=" + Path.GetFileName( filePath ) );
HttpContext.Current.Response.AddHeader( "Content-Length", fileSize.ToString() );
HttpContext.Current.Response.BinaryWrite( getContent );
}
...
}
If file name mentioned and stored in path/filePath variable contains space like
PR SimpleTest.xls
then the download box contains file name like PR with nothing additional.
If that file name has NO space (like PR_SimpleTest.xls) then the header comes with PR_SimpleTest.xls and I can download as such (appears full filename with his extension).
There are solution(s) to solve issue in case when file name contains space(s) ?
A google search for http headers spaces finds this Knowledge Base article which suggests surrounding the filename with quotes. E.g.
HttpContext.Current.Response.AddHeader(
"Content-Disposition",
"attachment; filename=\"" + Path.GetFileName( filePath ) + "\"");
The answer above using:
Server.UrlEncode(strFileName)
did not work for me, it resulted in a filename that was:
"My+Long+Filename.txt"
whereas the first solution using surrounding the filename with quotes produces:
"My Long Filename. txt"
which is what we want.
I think you use Firefox. Look at this link: Downloading file issue
Response.AppendHeader("content-disposition", "attachment; filename=" + Server.UrlEncode(strFileName))
Also look at ASP.NET MVC Uploading and Downloading Files and Writing A Custom File Download Action Result For ASP.NET MVC. In MVC you can use special action results.
HttpContext.Current.Response.AddHeader(
"Content-Disposition",
"attachment; filename=\"" + filePath + "\"");

save the document created by docX into response and send it to user for downloading

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.

Categories

Resources