I would like to view a PDF file directly in my browser. I know this question is already asked but I haven't found a solution that works for me.
Here is my action's controller code so far:
public ActionResult GetPdf(string fileName)
{
string filePath = "~/Content/files/" + fileName;
return File(filePath, "application/pdf", fileName);
}
Here is my view:
#{
doc = "Mode_d'emploi.pdf";
}
<p>#Html.ActionLink(UserResource.DocumentationLink, "GetPdf", "General", new { fileName = doc }, null)</p>
When I mouse hover the link here is the link:
The problem with my code is that the pdf file is not viewed in the browser but I get a message asking me if I wand to open or save the file.
I know it is possible and my browser support it because I already test it with another website allowing me to view pdf directly in my browser.
For example, here is the link when I mouse hover a link (on another website):
As you can see there is a difference in the generated link. I don't know if this is useful.
Any idea how can I view my pdf directly in the browser?
The reason you're getting a message asking you to open or save the file is that you're specifying a filename. If you don't specify the filename the PDF file will be opened in your browser.
So, all you need to do is to change your action to this:
public ActionResult GetPdf(string fileName)
{
string filePath = "~/Content/files/" + fileName;
return File(filePath, "application/pdf");
}
Or, if you need to specify a filename you'll have to do it this way:
public ActionResult GetPdf(string fileName)
{
string filePath = "~/Content/files/" + fileName;
Response.AddHeader("Content-Disposition", "inline; filename=" + fileName);
return File(filePath, "application/pdf");
}
Instead of returning a File, try returning a FileStreamResult
public ActionResult GetPdf(string fileName)
{
var fileStream = new FileStream("~/Content/files/" + fileName,
FileMode.Open,
FileAccess.Read
);
var fsResult = new FileStreamResult(fileStream, "application/pdf");
return fsResult;
}
Change your code to this :
Response.AppendHeader("Content-Disposition","inline;filename=xxxx.pdf");
return File(filePath, "application/pdf");
If you read the file stored in database image column, you can use like this:
public ActionResult DownloadFile(int id)
{
using (var db = new DbContext())
{
var data =
db.Documents.FirstOrDefault(m => m.ID == id);
if (data == null) return HttpNotFound();
Response.AppendHeader("content-disposition", "inline; filename=filename.pdf");
return new FileStreamResult(new MemoryStream(data.Fisier.ToArray()), "application/pdf");
}
}
If you are using Rotativa package to generate PDF, Then don't put a name to file with FileName attribute like below example.
return new PartialViewAsPdf("_JcPdfGenerator", pdfModel);
Hope this is helpful to someone.
Although previous posts are often correct; I think most of them are not best practice!
I'd like to suggest to change action return types to FileContentResult and usereturn new FileContentResult(fileContent, "application/pdf"); at the end of action body.
Yes You Can do It Simply by redirecting . it ends extension like u need , .pdf ..
protected void OpenPdfPdf_Click(object sender, EventArgs e)
{
Response.Redirect("jun.pdf");
}
Or another Method ,its opens like .aspx page--
protected void OpenPdf_Click(object sender, EventArgs e)
{
string path = Server.MapPath("jun.pdf");
//or you want to load from url change path to
//string path="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
WebClient client = new WebClient();
Byte[] buffer = client.DownloadData(path);
if (buffer != null)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", buffer.Length.ToString());
Response.BinaryWrite(buffer);
}
}
Related
I have a mvc 5 application, I save letters files in folder inside folder like (~\Files\Letters) and I save the physical path in database, uploading letters files to (~\Files\Letters) works fine and saving the physical path works fine, the problem is downloading a letter file to client machine, I have tried using Webclient and Response both don't work and don't give any error, here is the code for downloading a letter file using Response.
[HttpPost]
public void open(int id)
{
string path = "";
path = db.tblLetters.Where(t => t.ID == id).SingleOrDefault().LetterImg;
string fileName = path.Substring(path.LastIndexOf(#"\")+1);
string p = Server.MapPath("~/Files/LettersImgs/" + fileName);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.ContentType = "application/octet-stream";
Response.TransmitFile(p);
Response.End();
}
Rather than using old-style Response.TransmitFile, you can use FilePathResult to return file directly from server's file path. Change return type from void to ActionResult (or FileResult) and use [HttpGet] instead of [HttpPost], and do return File(...) to let user download the file like this example below:
[HttpGet]
public ActionResult Open(int id)
{
string path = "";
path = db.tblLetters.Where(t => t.ID == id).SingleOrDefault().LetterImg;
string fileName = path.Substring(path.LastIndexOf(#"\")+1);
string p = Server.MapPath("~/Files/LettersImgs/" + fileName);
return File(p, "application/octet-stream", fileName);
}
Related issue: How to download a file to client from server?
I have created a function where a user can download a pdf file from my webpage. The file is stored in a databse and is requested from a webapi. The return value of the webapi is a byte[].
My issue here is that when i run the web application on my local iis this function runs without any errors. I get the pdf file and it is downloaded correctly on my machine. But when i deploy the web application to my Test server this code generates either RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION in chrome with some of the files where as other files are downloaded to the machine but when i try to open the pdf file i get: could not load the pdf file.
This happens with both chrome and IE.
This is my code:
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
this.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
var result = File(translationFile.FileContent.Content, System.Net.Mime.MediaTypeNames.Application.Pdf, fileName);
return result;
}
I have been trying to fix this issue for 2 days now but i simply cant figure out what the issue is. Hope you guys can help. Thanks.
You don't need to use Content-Disposition. .Net will add it for you. From the docs.
The fileDownloadName parameter is used to generate the
content-disposition header. The result object that is prepared by this
method is written to the response by the ASP.NET MVC framework when
the object is executed. The MediaTypeNames class can be used to get
the MIME type for a specific file name extension.
I tend to use the Stream-overload:
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
var stream = = new MemoryStream(translationFile.FileContent.Content);
return File(stream, "application/pdf", fileName);
}
But you can use the byte[] as well:
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
return File(translationFile.FileContent.Content, "application/pdf", fileName);
}
EDIT:
If you got an error when opening the PDF you can ensure that the web browser is doing the right thing by manually saving the PDF from code as well. If that file has errors as well you're probably generating an incorrect byte[].
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
var stream = = new MemoryStream(translationFile.FileContent.Content);
// Code for debugging
var tempDir = "C:\\temp"; // Make sure app pool can write here.
var path = Path.Combine(tempDir, fileName); // Possibly add extension here.
using (var fileStream = File.Create(path))
{
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fileStream);
}
stream.Seek(0, SeekOrigin.Begin);
// Return to client.
return File(stream, "application/pdf", fileName);
}
I am generating dynamic .pdf file using asp.net, on some browsers e.g firefox displays the pdf as expected but on I.E & Safari its giving a "Save As" rather than displaying it in the browser. I have used an iFrame for the same. Also to display pdf file is it mandate that the client should have adobe reader or some plugin to display the pdf?
protected void bttnpdf_Click(object sender, EventArgs e)
{
string FilePath = Server.MapPath("sample.pdf");
WebClient User = new WebClient();
Byte[] FileBuffer = User.DownloadData(FilePath);
if (FileBuffer != null)
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", FileBuffer.Length.ToString());
Response.BinaryWrite(FileBuffer);
}
}
Any help would be appreciated.
Thanks in advance
in aspx file :
<div>
<iframe id="myFrame" runat="server" style="width:600px; height:500px;" frameborder="0"></iframe>
</div>
in cs file :
myFrame.src="yourPDFPath"
for example
myFrame.Src = "http://docs.google.com/gview?url=http://path.com/to/your/pdf.pdf&embedded=true";
When I have done this I have also added a content disposition. In the code (can't share it all as it is production code) there is a function that finds a record in the database and returns a FileHandle.
The function returns a FileHandle:
FileStream stream = new FileStream(filePath, FileMode.Open);
var fileHandle = new FileHandle
{
FileStream = stream,
ContentType = "application/pdf",
Filename = fileDownloadName
};
where filePath is the path to the file (e.g. Server.MapPath("sample.pdf") ). In the controller action I have:
var cd = new System.Net.Mime.ContentDisposition
{
// for example foo.bak
FileName = fileHandle.Filename,
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(fileHandle.FileStream, fileHandle.ContentType);
Add below line before the line Response.BinaryWrite(FileBuffer);.
Response.AddHeader("Content-Disposition", "inline");
add this header to reponse , so that PDF files will opened in browser itself.
Hi all wondering if someone can help; i've written this code which will generate an excel spreadsheet and save it to a specified location. I want to then display a "Save as" dialogue box by reading the file from the stored location and then asking then user where they want to store it. The excel file is being generated fine and i can open it normally! However my problem is the code i've written seems to be outputting the file directly to my browser, so i get all the contents of the excel file on my browser screen, not displaying the save as dialogue box as expected!
public ActionResult FormSuccess()
{
String FileName = System.Configuration.ConfigurationManager.AppSettings["FileName"].ToString();
String FilePath = System.Configuration.ConfigurationManager.AppSettings["FileSaveLocation"].ToString();
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "application/vnd.xls";
response.AddHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
response.TransmitFile(FilePath + FileName);
response.End();
return PartialView("FormSuccess");
}
Yo Vince, how's tricks? Still wearing the medallion? :)
Shouldn't you be using FileContentResult instead of PartialView? You won't be able to return the file AND the HTML "success" content in the same call - you should probably call the PartialView first, which would then use javascript to open the FileContentResult URL in a new window.
See this: http://www.mikesdotnetting.com/Article/125/ASP.NET-MVC-Uploading-and-Downloading-Files
and this url as well :
http://weblogs.asp.net/rajbk/archive/2010/05/03/actionresult-types-in-mvc2.aspx
I think that your problem is that you return PartialView. Let me give you small exmaple of my implemetation:
public ActionResult FileXls()
{
var output = new MemoryStream();
var writer = new StreamWriter(output);
//create your workbook excel file
....
//workbook.Save(output);
writer.Flush();
output.Position = 0;
return File(output, "text/excel", "file.xls");
}
I have a number of pages which need to support exporting data to an Excel spreadsheet. I can generate the Excel files just fine, but I'm trying to work out how to abstract this behavior so it's easily reusable from all of the pages where I need it. My current idea is to use a static utility method, as follows:
public static void SendExcelFile(System.Web.UI.Page callingPage, string downloadFileName, List<List<string>> data, string worksheetTitle)
{
string tempFileName = Path.GetTempFileName();
try
{
// Generate file using ExcelPackage
GenerateExcelDoc(tempFileName, data, worksheetTitle);
callingPage.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
callingPage.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
callingPage.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
callingPage.Response.TransmitFile(tempFileName);
}
finally
{
//When this is removed, the method works as expected.
if (File.Exists(tempFileName))
File.Delete(tempFileName);
}
}
The click handler where I'm calling SendExcelFile looks like this:
protected void lnkExport_Click(object sender, EventArgs e)
{
List<List<string>> dataList = GatherDataForSpreadsheet();
Utility.SendExcelFile(this, "fileNameForDownload.xlsx", dataList, "MyReports");
}
This code works just fine as an instance method of the calling page. As a static method, though, it doesn't work at all. When I click the button that invokes this, the browser shows the loading animations indefinitely, but never prompts for a file download.
I'm very new to ASP.NET (and web programming in general), so I'm sure I'm missing something here. Could someone please explain the behavior I'm seeing, and suggest a reasonable alternative to this approach?
EDIT: If I remove the call to File.Delete() at the end, the method works as expected. Does Response.TransmitFile() do the transfer asynchronously?
EDIT 2: I just needed to call Response.Flush() before I deleted the file. See my answer below.
Thanks!
The problem was that the temp file was being deleted before the data was sent down. I just needed to call Response.Flush() like so:
public static void SendExcelFile(System.Web.UI.Page callingPage, string downloadFileName, List<List<string>> data, string worksheetTitle)
{
string tempFileName = Path.GetTempFileName();
try
{
// Generate file using ExcelPackage
GenerateExcelDoc(tempFileName, data, worksheetTitle);
callingPage.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
callingPage.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
callingPage.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
callingPage.Response.TransmitFile(tempFileName);
callingPage.Response.Flush(); //This is what I needed
}
finally
{
if (File.Exists(tempFileName))
File.Delete(tempFileName);
}
}
Try this, you can get the Request and Response directly off HttpContext.Current:
public static void SendExcelFile(string downloadFileName, List<List<string>> data, string worksheetTitle)
{
var context = HttpContext.Current;
string tempFolder = context.Request.PhysicalApplicationPath + "temp";
string tempFileName = tempFolder + "tempFileName.xlsx"
if (!Directory.Exists(tempFolder))
Directory.CreateDirectory(tempFolder);
// Generate file using ExcelPackage
GenerateExcelDoc(tempFileName, data, worksheetTitle);
context.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
context.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
context.Response.TransmitFile(tempFileName);
File.Delete(tempFileName);
}
Another alternative is a base class for your pages that contains this method, that may be a much easier route. You pages don't have to inherit from System.Web.UI.Page, they can inherit from something else, like this:
public class BasePage : System.Web.UI.Page
{
public void SendExcelFile(string downloadFileName, List<List<string>> data, string worksheetTitle)
{
string tempFolder =Request.PhysicalApplicationPath + "temp";
string tempFileName = tempFolder + "tempFileName.xlsx"
if (!Directory.Exists(tempFolder))
Directory.CreateDirectory(tempFolder);
// Generate file using ExcelPackage
GenerateExcelDoc(tempFileName, data, worksheetTitle);
Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
Response.TransmitFile(tempFileName);
File.Delete(tempFileName);
}
}
Then in your page the class looks like:
public partial class MyPage : BasePage
{
//Stuff!
}
We need more information - what you're doing should work.
I created a stripped-down version that just sends a copy of the calling page to the client and it works as expected:
public class Utility {
// This just sends the client a copy of the calling page itself
public static void SendExcelFile(Page callingPage) {
string path = callingPage.Request.PhysicalPath;
callingPage.Response.AddHeader("Content-Disposition", "attachment;filename=test.xls");
callingPage.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
callingPage.Response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
callingPage.Response.TransmitFile(path);
}
}
Here's my calling page:
public partial class main : System.Web.UI.Page {
protected void SendButton_Click(object sender, EventArgs e) {
Utility.SendExcelFile(this);
}
}
Do you see any differences from your implementation?
At this point I'd use an HTTP debugging proxy like Fiddler to compare the HTTP sessions generated by both the working (page codebehind) and nonworking (static) versions of your code.
As an aside, you should be aware that your code as written won't work well if more than one user clicks the button at the same time -- the first user's temp file may get overwritten by the second user's file, and the second user's file may get deleted in the middle of being transmitted! Consider using Path.GetTempFileName() or a guid in the filename to ensure that each user's file is uniquely named.
I would use this instead. The current HTTP context will be available on every page.
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + downloadFileName);
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.AddHeader("Content-Length", new FileInfo(tempFileName).Length.ToString());
HttpContext.Current.Response.TransmitFile(tempFileName);