Why doesn't my PDF document render/download in ASP.NET MVC2? - asp.net-mvc

I have an ASP.NET MVC2 application in development and I am having problems rendering a .pdf file from our production server.
On my Visual Studio 2010 integrated development server everything works fine, but after I publish the application to the production server, it breaks. It does not throw any exceptions or errors of any kind, it simply does not show the file.
Here's my function for displaying the PDF document:
public static void PrintExt(byte[] FileToShow, String TempFileName,
String Extension)
{
String ReportPath = Path.GetTempFileName() + '.' + Extension;
BinaryWriter bwriter =
new BinaryWriter(System.IO.File.Open(ReportPath, FileMode.Create));
bwriter.Write(FileToShow);
bwriter.Close();
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = ReportPath;
p.StartInfo.UseShellExecute = true;
p.Start();
}
My production server is running Windows Server 2008 and IIS 7.

You cannot expect opening the default program associated with PDF file browsing on the server. Try returning the file into the response stream which will effectively open it on the client machine:
public ActionResult ShowPdf()
{
byte[] fileToShow = FetchPdfFile();
return File(fileToShow, "application/pdf", "report.pdf");
}
And now navigate to /somecontroller/showPdf. If you want the PDF opening inside the browser instead of showing the download dialog you may try adding the following to the controller action before returning:
Response.AddHeader("Content-Disposition", "attachment; filename=report.pdf");

i suggest you use ASP.NET MVC FileResult Class to display the PDF.
see http://msdn.microsoft.com/en-us/library/system.web.mvc.fileresult.aspx
your code open`s the PDF on the webserver.

Here's how I did it.
public ActionResult PrintPDF(byte[] FileToShow, String TempFileName, String Extension)
{
String ReportPath = Path.GetTempFileName() + '.' + Extension;
BinaryWriter bwriter = new BinaryWriter(System.IO.File.Open(ReportPath, FileMode.Create));
bwriter.Write(FileToShow);
bwriter.Close();
return base.File(FileToShow, "application/pdf");
}
Thank you all for your efforts. Solution I used is the most similar to the Darin's one (almost the same, but his is prettier :D), so I will accept his solution.
Vote up for all of you folks (both for answers and comments)
Thanks

Related

Authentication fail error on convert Html to Pdf

I try to convert Html to PDF use "HtmlToPdf" nuget , It was work fine on local test but when i upload site to host i get this error :
Conversion error: Authentication error.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Exception: Conversion error: Authentication error.
This is my Convert method Code
[AllowAnonymous]
public ActionResult Convert(int id)
{
HtmlToPdf converter = new HtmlToPdf();
var context = System.Web.HttpContext.Current;
string baseUrl = context.Request.Url.Host + ":"+context.Request.Url.Port + "/Doctor/DietTherapy/LineRegimePrint/";
PdfDocument doc = converter.ConvertUrl(baseUrl + id);
// save pdf document
byte[] pdf = doc.Save();
// close pdf document
doc.Close();
// return resulted pdf document
FileResult fileResult = new FileContentResult(pdf, "application/pdf");
fileResult.FileDownloadName = "Document.pdf";
return fileResult;
}
How can i authorize user for this convert ?
It sounds like you just need to authenticate the request being made by the PDF library. For example, if it's using Basic HTTP Authentication:
HtmlToPdf converter = new HtmlToPdf();
converter.Options.Authentication.Username = "some username";
converter.Options.Authentication.Password = "some password";
// the rest of your code...
The linked documentation also contains examples for other authentication methods.
Did you check to see if you're getting the proper value on this line of code (when running on host server)?
string baseUrl = context.Request.Url.Host + ":"+context.Request.Url.Port + "/Doctor/DietTherapy/LineRegimePrint/";
While your development machine's IIS Express uses Anonymous Authentication, your hosting server is probably using Windows Authentication or other kinds. Check the IIS Managers to see the difference.
SelectPDF's library somehow creates a separate process to perform the HtmlToPdf conversion, which is outside the IUser, and therefore, the server asks for authentication.
For Windows Authentication setting, you may just use a generic user login account for this purpose and populate the required properties as mentioned in above thread and all would be fine.
converter.Options.Authentication.Username = "WindowsUser";
converter.Options.Authentication.Password = "WindowsPassword";

Save file to path desktop for current user

I have a project ASP.NET Core 2.0 MVC running on IIS.
Want to Export some information from data grid to Excel and save it from web page to the desktop of current user.
string fileName = "SN-export-" + DateTime.Now + ".xlsx";
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
fileName = rgx.Replace(fileName, ".");
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string fileName2 = Path.Combine(path, fileName);
FileInfo excelFile = new FileInfo(fileName2);
excel.SaveAs(excelFile);
This works perfect local at Visual Studio, but not after publishing at IIS.
Using simple path string path = #"C:\WINDOWS\TEMP"; It will save this export file at the server temp folder, but not current web page user.
How to get this?
ASP.NET MVC is framework for a web application. So you have fronted and backend parts. This code will executed on the server side of your application. Even if you use Razor pages, they also generated at the backend. So there are several ways to save data on the computer:
use js to iterate data and save it, but I'm not sure that saving to excel with js is easy;
send desired data to backend, save it to excel and then return to the client.
For a second way you can use next code:
[Route("api/[controller]")]
public class DownloadController : Controller {
//GET api/download/12345abc
[HttpGet("{id}"]
public async Task<IActionResult> Download(YourData data) {
Stream stream = await {{__get_stream_based_on_your_data__}}
if(stream == null)
return NotFound();
return File(stream, "application/octet-stream"); // returns a FileStreamResult
}
}
And because of security reasons you can save data only to downloads directory.

Controller gives directory browsing rather than returning text

I have the following action method:
public ActionResult Index(string filename)
{
string detailFolder = SSOSettingsFileManager.SSOSettingsFileReader.ReadString("bts.go.core", "SupportNotificationDetailPath");
string pathFile = System.IO.Path.Combine(detailFolder, filename);
XDocument xdoc = XDocument.Load(pathFile);
XNamespace ns = "http://BTS.GO.Core.Schemas.SupportNotificationDetail";
var notificationMsg = from x in xdoc.Descendants("NotificationMessage") select x.Value;
var content = HttpUtility.HtmlDecode(notificationMsg.FirstOrDefault());
IHtmlString htmlContent = new HtmlString(content);
SupportNotificationDetailViewModel vm = new SupportNotificationDetailViewModel();
vm.Content = htmlContent;
return View(vm);
}
This works fine when deployed into my dev machine.The view calls the action and is returned the text content of the "NotificationMessage"element, which it renders on screen, as shown below:
My problem is, with the same site deployed to my test server. When I click the link that executes the action, rather than being presented with text, I get a directory listing of the content of the folder contained in the variable detailFolder, as shown below:
I guess this must be down to a difference in the IIS config. I tried using msdn link to figure it out but no luck. The command for msdeploy comes back with "Cannot create a file when that file already exists.". I find this strange because I used web deploy to deploy the website to both servers. Both machines are running server 2012r2
The bad server has the following Windows Features installed (should be all that's needed?):
Any ideas?

PDF JS, from file location

I have successfully set up using the viewer with the following code:
protected void btnShowPDFS_OnClick(object sender, EventArgs e)
{
// Display all files.
string[] files = Directory.GetFiles(#"D:\Reports\2014\July\", "*.PDF");
var pdfNames = new List<string>();
foreach (string file in files)
{
string fileName = Path.GetFileName(file);
string queryString = "/web/viewer.html?file=" + System.Web.HttpUtility.UrlEncode("../July/" + fileName);
pdfNames.Add(queryString);
}
listView.DataSource = pdfNames;
listView.DataBind();
}
Now, this all works fine if all my PDF's are in a folder within the website (i.e localhost). However, how do i point the view to either a network share, or just another folder on the same machine, but outside of IIS?
A browser's XMLHttpRequest might have a restrictions for local files access (Firefox has more relaxed policy for local file than other browsers).
PDF.js is using XHR; and PDF.js also allows "load" files from a typed array (Uint8Array). You can use the latter in your solution. Notice the Internet Explorer (WebBrowser control) has window.external that can be used to transmit the data from the host application, see http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting(v=vs.110).aspx

ASP.NET MVC open pdf file in new window

I have a MVC application. I need to open the pdf file when user clicks the open button on the page. The filepath where the pdf is stored is read from the database and it is a file on c:. How do I open it in my html code? I have this code:
Open
but this doesn't open my file. What do I have to do? I need to specify somewhere that it is a pdf??
You will need to provide a path to an action that will receive a filename, resolve the full path, and then stream the file on disk from the server to the client. Clients out in the web, thankfully, cannot read files directly off your server's file system (unless... are you suggesting #Model.CertificatePath is the path to the file on the remote user's machine?).
public ActionResult Download(string fileName)
{
string path = Path.Combine(#"C:\path\to\files", fileName);
return File(path, "application/pdf");
}
Update
If #Model.CertificatePath is the location on the client's actual machine, try:
Open
Note that some browsers may have security settings disallowing you from opening local files.
Try like this in your View
#Html.ActionLink("View", "ViewPDF", new { target = "_blank" })
Now Link will open in new window. You can write the pdf bytes in ViewPDF controller method
You could have the link fire a method such as the one below which will then stream your chosen file to the file download rather than opening the pdf in the broswer.
/// <summary>
/// Forces a file to be displayed to the user for download.
/// </summary>
/// <param name="virtualPath"></param>
/// <param name="fileName"></param>
public static void ForceDownload(string virtualPath, string fileName)
{
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.AddHeader("content-disposition", "attachment; filename=" + fileName);
response.WriteFile(virtualPath);
response.ContentType = "";
response.End();
}
Well if your getting the path value and the value is in #Model.CertificatePath
this wiil not work
Open
You will need to add this
Open
and make sure you path is relative by adding this ~
for example if your path is /Content/pdfs/CertificatePath.pdf
it would need to look like
~/Content/pdfs/CertificatePath.pdf
This should be the simplest way to make it work.
Hope this helps.
Unfortunately you can't dictate where the PDF will be opened, mainly because you can't guarantee the Adobe Acrobat reader plugin is installed or how it functions.
You could in theory open a new window, and in that new window have a JavaScript function to open the PDF file, but again you can't guarantee it will open in a embedded window without the plugin, the best you can hope for is "best try".

Resources