Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Sunday, February 8, 2015 8:27 AM
I am trying to save my webpage in a pdf format. The file has to saved in the same location as I can show it.
public FileStreamResult PDFGenerator(string html, string fileName)
{
string fullFileName = Environment.GetFolderPath(Environment.SpecialFolder.MyDownloads) + fileName + ".pdf";
Stream fileStream = CreatePDF(html, fullFileName);
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
return new FileStreamResult(fileStream, "application/pdf");
}
The FileStreamResult search the path in "///C:/Users/Me/Downloads/".
So I want to save the pdf-document in the same folder.
How do you do that?
The fullFileName string has to referred to the same location as FileStreamResult.
All replies (15)
Tuesday, February 17, 2015 4:39 PM âś…Answered
This is my result that works:
This is calling from the View
public HttpResponseBase HitlijstNaarPdf(int? AID_Hitlijst = 0)
{
SelectPeriode(AID_Hitlijst);
var model = new HitlijstModel();
GetHitlijstSettings();
string sHtmlInhoud = ViewRenderer.RenderView("Hitlijst", model, ControllerContext);
string fileName = "Hitlijst_" + AID_Hitlijst.ToString() + ".pdf";
return CreatePDF(sHtmlInhoud, fileName);
}
private HttpResponseBase CreatePDF(string html, string fileName)
{
string convertingTool = Server.MapPath("~/bin/wkhtmltopdf.exe ");
ProcessStartInfo psi = new ProcessStartInfo(convertingTool);
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardError = true;
psi.CreateNoWindow = true;
Process myProcess = Process.Start(psi);
myProcess.WaitForExit();
myProcess.Close();
string fullFileName = Server.MapPath("~/Documenten/" + fileName);
if (!System.IO.File.Exists(fullFileName))
{
Document pdfDocument = new Document(PageSize.A4, 30, 30, 30, 30);
PdfWriter writer = PdfWriter.GetInstance(pdfDocument, new FileStream(fullFileName, FileMode.Create));
PdfWriter.GetInstance(pdfDocument, Response.OutputStream);
pdfDocument.Open();
XMLWorkerHelper.GetInstance().ParseXHtml(writer, pdfDocument, new StringReader(html));
pdfDocument.Close();
}
Response.Clear();
WebClient client = new WebClient();
Byte[] buffer = client.DownloadData(fullFileName);
Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
Response.ContentType = "application/pdf";
Response.BinaryWrite(buffer);
return Response;
}
... and thanks for your useful reactions.
Sunday, February 8, 2015 8:53 AM
Hi,
You can't to keep the user in control. The "download" folder will be likely the "Download" folder by default and is usually handled with a download managet but the user is kept in control and can choose the final location as he wish.
Note also that Environment.GetFolderPath(Environment.SpecialFolder.MyDownloads) may appear to work fine on your own dev box but that it runs SERVER SIDE and won't give the expected result when it runs on a "real" web server (IMO you are expected to just provide a file name).
Sunday, February 8, 2015 8:57 AM
The most important is: The fullFileName string has to referred to the same location as FileStreamResult.
- What is the dynamic folder-location of FIleStreamResult?
- Can I manage it?
Sunday, February 8, 2015 1:23 PM
Still unclear as YOU decide of the fullname and opens the Stream using the same location. But it is striclty a server side location and the content disposition allows just to define a default file name.
The user is still able to select the final location (and likkely even rename the file if he wants).
For now it seems you are confusing the server side and the client side location (keep in mind that this code runs server side so Environment.GetFolderPath(Environment.SpecialFolder.MyDownloads) just give Something that makes sense on your dev box (as the client and server machine are the same) but it would be meaningless on a "real" web server.
Edit: so the steps would be decide where to save your file. This is a server side location. Stream the file from there with a hint for the file name. The user sees the download manager and is able to save the file where he wants.
Sunday, February 8, 2015 2:25 PM
If FileStreamResult shows "///C:/Users/Me/Downloads/MyFile123.pdf", then has to be created MyFile123.pdf in C:/Users/Me/Downloads/.
The function Environment.SpecialFolder.MyDownloads doesn't exist in .NET. But why do the FileStreamResult shows "///C:/Users/Me/Downloads/MyFile123.pdf" in the browser? What is the reason and how can I make a command
string fullFileName = Environment.GetFolderPath(Environment.SpecialFolder.FileStreamResultDirectory) + fileName + ".pdf";
What do I have to do? If this is wrong way of thinking. Where do I save the MyFile123.pdf-file? Which dynamically location?
Sunday, February 8, 2015 3:38 PM
a FileStreamResult is just a stream. you can not tell the browser where to store it, the user does that with their save dialog (though most browser just stuff it in downloads). The server can hint the name (not the path), via using attachment mime type.
Sunday, February 8, 2015 4:34 PM
And if I place it in
string fullFileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + fileName + ".pdf";
Do I have to set something maybe in the web.config?
Sorry help me... I am only want to click on a button and the pdf-file will be downloaded and showing on a page in the browser that's everything I want.
{I think it will placed somewhere on the machine. I don't care where. And I have tried everything. But every solution I tried was wrong. So the only thing I wanna know is something that works. I don't care what.}
Monday, February 9, 2015 4:07 AM
Hi Wesley,
From your description, you want user download the pdf file when click the download button and then show this pdf on the page.
First, I don't think we can control client where to save the pdf file. Even if the client save the file to the specify place, I still don't think we can access the local file of the client.
So I think, if you want to show the pdf file after download, you could still get this pdf file from server. Then the one most important thing is How to know when the download is complete.
About this question, my suggestion is once the user click the download button and start downloading, we think this operation successful, then you could transfer to new page and show that pdf file.
Hope this can be helpful to you.
Sherwin Zhao
Best Regards
Monday, February 9, 2015 4:36 AM
You definitely confuse client and server location. Keep in mind that your code runs server side so it may appear to kind of work on your dev box because the server and the client are the same but using Environment.GetFolderPath is meaningless server side (at best you would have a folder for the account under which your web application runs and it will be entirely unrelated to a client side location).
So you can define whatever *server side* directory you want for temporary files or even better no directory at all. Your PDF Library can likely create a Stream you could send directly to the browser so that you don't even have to save a file somewhere.
The filename is part of the content disposition and is just a suggestion about how to name the file. The user is still in control of the final file location (and likely could also rename it if he wants).
If you want to show a PDF file inside a web page you could use the object tag : http://www.w3schools.com/tags/tag_object.asp
If you want to let the user to download and possibly open the file externally by the viewer, your approach is correct.
Tuesday, February 10, 2015 6:21 PM
This is the full source:
Here is calling the Action (in the View):
<td><span>
<a href='<%: Url.Action("HitlijstNaarPdf", new { AID_Hitlijst = ViewBag.Huidig })%>' target="_blank">Download lijst</a>
</span>
</td>
Here in the controller:
public FileStreamResult HitlijstNaarPdf(int? AID_Hitlijst = 0)
{
SelectPeriode(AID_Hitlijst);
var model = new HitlijstModel();
GetHitlijstSettings();
//string sHtmlInhoud = this.RenderView("Index", model);
string sHtmlInhoud = ViewRenderer.RenderView("Index", model, ControllerContext);
FileStreamResult result = PDFGenerator(sHtmlInhoud, "Hitlijst_" + AID_Hitlijst.ToString());
return result;
}
public FileStreamResult PDFGenerator(string html, string fileName)
{
//string fullFileName = Server.MapPath("~/Documenten/" + fileName + ".pdf");
//string fullFileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Temp\" + fileName + ".pdf";
Stream fileStream = CreatePDF(html, fileName);
HttpContext.Response.AddHeader("content-disposition", "inline; filename=" + fileName);
or
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
return new FileStreamResult(fileStream, "application/pdf");
}
private MemoryStream CreatePDF(string html, string fullFileName)
{
MemoryStream msOutput = new MemoryStream();
TextReader reader = new StringReader(html);
Document pdfDocument = new Document(PageSize.A4, 30, 30, 30, 30);
PdfWriter writer = PdfWriter.GetInstance(pdfDocument, new FileStream(fullFileName, FileMode.Create));
PdfWriter.GetInstance(pdfDocument, Response.OutputStream);
pdfDocument.Open();
XMLWorkerHelper.GetInstance().ParseXHtml(writer, pdfDocument, new StringReader(html));
pdfDocument.Close();
//pdfDocument.LoadFromHTML(url, false, true, true);
return msOutput;
}
And it look likes the file will created twice. Can someone tell what I'm doing wrong?
If everything works fine, you see "a pdf-file" with content, you can open and you can show it.
Thursday, February 12, 2015 11:48 PM
Hi Wesley,
Please try the following code:
public FileStreamResult HitlijstNaarPdf(int? AID_Hitlijst = 0)
{
Stream stream = CreatePDF(AID_Hitlijst )
return File(stream, "application/pdf", "myPDF.pdf");
}
After you get the pdf stream, directly return File.
Hope this can be helpful to you.
Sherwin Zhao
Best Regards
Friday, February 13, 2015 5:11 AM
It looks like vicious cirkle.
Or you get this:
C:\Users\Me\Downloads\C--eSoft-Extended-eHMCWebSolution-eHMCWeb-Documenten-Hitlijst_198743.pdf
Or you get this:
ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION
Or you get this:
System.UnauthorizedAccessException: Access to the path C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\11.0\Hitlijst_198743 is refused.
At the end of the process. Everytime the PATH is wrong. I need to know How can I bring the system to the right folder (That's right the folder has to be Virtual or something) It is possible on other websites. So there MUST be a solution...
Monday, February 16, 2015 4:03 AM
Hi Wesley,
Or you get this:
C:\Users\Me\Downloads\C--eSoft-Extended-eHMCWebSolution-eHMCWeb-Documenten-Hitlijst_198743.pdf
Or you get this:
ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION
Or you get this:
System.UnauthorizedAccessException: Access to the path C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\11.0\Hitlijst_198743 is refused.
What are these file paths? The source file path in server or the downloaded file path in client.
And there is a very important point, we can't control the position of the user saved the file. if you want to show the file, you could try to load the file of the server. I think the file same as the downloaded file.
Hope this can be helpful to you.
Sherwin Zhao
Best Regards
Monday, February 16, 2015 5:52 AM
I have reserved a location on my server. That was my first intention. I can create that. But how can I call it by using
public FileStreamResult PDFGenerator(string html, string fileName)
{
string fullFileName = Server.MapPath("~/Documenten/" + fileName + ".pdf");
Stream fileStream = CreatePDF(html, fullFileName);
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + fullFileName);
return new FileStreamResult(fileStream, "application/pdf");
// or this...
return File(fileStream, "application/pdf", fullFileName);
}
Tuesday, February 17, 2015 12:34 AM
Hi Wesley,
string fullFileName = Server.MapPath("~/Documenten/" + fileName + ".pdf"); Stream fileStream = CreatePDF(html, fullFileName);
You could generate the pdf to your specify location. Because it's on server.
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + fullFileName);
You returned the full path of the generated file, it's still ok. But maybe client not wish to save the file to your specify location. They can save this file to any location. So maybe you can't load the file from the client pc.
And if you want to load this file from server(not client), please refer to the following link
http://forums.asp.net/t/1219837.aspx?Open+PDF+file+on+button+click+or+hyperlink+from+asp+net
Sherwin Zhao
Best Regards