Make PDF display inline instead of separate Acrobat Reader window - asp.net

I've got an ASP.NET ashx class that retrieves data from a database, creates a PDF file using iTextSharp, and streams the PDF to the browser. The browser (IE and Firefox at least) is launching Acrobat Reader as a separate window to open the file. I'd like for it to display inline within the browser.
Is that something I can completely control from the server side? I'm already setting the Content-Type header to application/pdf, and I've tried setting Content-Disposition and Content-Length. Nothing so far has worked.
Is there another header I'm missing? Is there something in the PDF itself that tells the browser how to display it? Any other ideas?

Setting the content-disposition and content-type headers should do it, but you might also need to call Response.ClearHeaders() to clear other headers that have been set.
Also, try using Fiddler to see the actual headers and content from the response and compare them to those from a site that works like you want.

If you are using an ashx (web handler) try this:-
context.Response.AddHeader("content-disposition", "inline; filename=Something.pdf")

OK, turns out it was a stupid question, but I'm glad I asked it because I had never heard of Fiddler (which led me to the answer, which is why I'm accepting tspauld's answer). The PDF is generated by a web service that serves the file to a couple of different front-end sites. I was setting the content disposition to inline in the service, but that didn't matter, because the browser never got that header; it got the header from the front-end site (which was attachment). I changed it in the front-end site and that fixed it.
So the answer is that you have to have Content-Type=application/pdf and Content-Disposition=inline; filename=Something.pdf, as others have said.

Try generating them into your page using html OBJECT.
<OBJECT WIDTH=640 HEIGHT=480>
<PARAM NAME="SRC" VALUE="<%=filePath%>">
<EMBED SRC=<%=filename.pdf%> WIDTH=1000 HEIGHT=680>
<NOEMBED> PDF should have displayed here!</NOEMBED>
</EMBED>
</OBJECT>
If you need to stream the response with an ashx instead of being able to return an aspx, I think you may be out of luck.
Otherwise, I believe the settings to show in browser or not, is completely client driven and out of your hands.

So, I have a sample in one of my works that is what you need:
<cc1:ShowPdf ID="ShowPdf1" runat="server" BorderStyle="None" BorderWidth="0px"
Height="750px" Style="z-index: 103; "
Width="750px"/>
and in server side :
ShowPdf1.FilePath = String.Format("~/Handlers/Pdf.ashx?id={0}#view=FitH&page=1&pagemode=none&navpanes=1", myPublicationId);
I place here also some code from my PDF Handler :
Response.ContentType = "application/pdf";
byte[] bytes = YourBinaryContent;
using (BinaryWriter writer = new BinaryWriter(context.Response.OutputStream))
{
writer.Write(bytes, 0, bytes.Length);
}
Anyway If my post doesn't seem clear to you, have a look at this sample How to Display PDF documents with ASP.NET

I think this header will do what you want
Content-type: application/pdf
Since you say that is not working, then I suspect it is a configuration setting on the client side.
Check your installed version of Adobe Acrobat. There is a setting in preferences for "Internet" and a checkbox that says "Display PDF in Browser".
--
bmb

Here is an article on using the embed tag to do it:http://blogs.adobe.com/pdfdevjunkie/2007/08/using_the_html_embed_tag_to_di.html

If you have the budget, my company sells a set of products that includes an AJAX based image viewer that will let you view the PDF pages in line without Acrobat at all. In its simplest form, it is just a viewer, but you can layer in interactivity as you need.

Related

Web form non-responsive after download

I'm working in ASP.NET (2.0) and we have a page where a user is able to select and download a series of files as a zip. I got this to work without undo difficulty by using the DotNetZip library (which is probably not relevant to the problem, but included for completeness.)
After the user checks which files they want to download, the page does a postback, and in the button click event handler, I use the following code:
Response.Clear();
Response.BufferOutput = false; // false = stream immediately
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "filename=FileRequest.zip");
using (ZipFile zip = new ZipFile())
{
zip.AddFile(MapPath("/datafiles/fileToZip.pdf"), "");
zip.Save(Response.OutputStream);
}
Response.Close();
And this all seems to work great. The user clicks the button, a download window pops up, the user downloads the zip. All is good...
...until they decide they want to do something else on the page. The buttons in the form are no longer responsive. For instance, if I click the download button again, it does nothing. If I reload the page, I can repeat this behavior...it works once, then does nothing.
I'm not understanding why the browser doesn't send the new request. It's not "spinning" or otherwise acting busy. I thought that this might be a browser issue, but I've repeated it in both IE and Firefox, so it seems likely that it's something I'm not understanding. Strangely, it's only form submission elements that seem to be non-responsive. Javascript still works, and so do regular links.
So why is this happening, and how do I get around it?
The problem is likely down to you returning;
Response.ContentType = "application/zip";
Once this has been sent (along with the actual content), the browser would assume it has nothing left to do (I believe).
You probably should create a new window specifically for downloading the files by saving the file selection in a session parameter (or equivalent) and opening a popup window that has your download code in.
This will leave the parent page in a suitable state.
Content-disposition header seems to be a discouraged solution. But the same effect of ASP.NET forms not being responsive occurs if you use standard Redirect to a zip file.
I solved very similar problem (returning *.csv files by the server for download) using Tančev Saša's code in "Response.Redirect to new window" Q&A and it works great. Perhaps it might produce some popup warnings in some browsers, but I think this is how it's often done in download sites.

ASP embed image to CDO.Message email

I'm using ASP classic and CDO to send email with CreateMHTMLBody method. I have couple of images in my email which some of them are static and would not change but some of them will change based on email content. Some of the mail softwares like iCloud showing the pictures as attachment even though I have them all with full path url address. I've used AddRelatedBodyPart but right now they show the images in the place that thy have to be but still they show the images in attachment as well. I want the picture just show in body of email not in attachment. Does any one know how to fix this? Here is the example of my code:
Set myMail=CreateObject("CDO.Message")
myMail.Subject= "Subject of Email"
myMail.From= "from#site.com"
myMail.To= "to#site.com"
myMail.CreateMHTMLBody "http://www.mysite.com/email.html"
strImagePath = Server.MapPath("\") & "\images\mypic1.jpg"
myMail.AddRelatedBodyPart strImagePath, "my_pic_1", 0
strImagePath = Server.MapPath("\") & "\images\mypic2.jpg"
myMail.AddRelatedBodyPart strImagePath, "my_pic_2", 0
myMail.Send
set myMail=nothing
Thanks in advance for your time and help.
In order to have images in emails, you have to use inline IMG tags in the body of the message with the fully-qualified path to the image (http://...). DO NOT treat them as attachments.
The CreateMHTMLBody is not what you need. This method will create a multipart message fetching the URL and post processing the HTML returned. It fetches the resource for every img src it finds, encodes the returned resource as a body part and updates the HTML img src to point at the body part.
Also CreateMHTMLBody is not a good thing to use in ASP code since it uses the WinINET Http stack to fetch resources, WinINET should not be used from ASP code.
What you really need is to use something like WinHTTP to fetch the HTML resource and then assign that to the Message's HTMLBody property.
I know this question is old but maybe you (or someone else) is still looking for the answer:
myMail.Configuration.Fields("urn:schemas:httpmail:content-disposition-type")="inline"
myMail.Configuration.Fields.Update
This should cause most mail clients to not render images as attachments.
true;
strImagePath = Server.MapPath("\") & "\images\mypic1.jpg"
response.write strImagePath ' try
myMail.AddRelatedBodyPart strImagePath, "mypic1.jpg", 0

openning files in another browser page/tab

i have an action that return a file content. i added:
Response.AddHeader("Content-Disposition", "attactment; filename:\"" + survey.File + "\"");
so that the image would be opened in another tab/page, gets opened in the current tab/page.
whats wrong with the header?
The content-disposition header instructs the user agent how it should present the data, and it is usually used when serving up binary data (as opposed to plain text). When set to "attachment", the display of the content is contingent upon further action of the user. In other words, the user should receive a prompt and must decide what to do with the content (usually given an "Open" or "Save" option).
You can not programmatically force a hyperlink to open up in a new tab. Even if you could, you should not. This behavior should be controlled by the user agent. As a user, when I want to open something in a new tab, I use the mouse-wheel-click because that is how my browser is configured.
You cannot control browser's tab behaviour by using HTTP headers - there is nothing in your code that affects this.
What might help you is changing HTML code that points to your download - if you are using tag you can set its target attribute to _tab or _blank and it will work in many browsers.

PDF wrong error in IE6 and IE7 with https

Response.Write("<script language=\"javascript\">window.open( with https and pdf
What we do in a Asp.Net 1.1.4332 application is the following:
a button triggers a server event that does some processing and puts the data in a session object after that the following code is executed :
string page = Request.ApplicationPath + "/ApkRapportPage.aspx";
Response.Write("<script language=\"javascript\">window.open('" + page + "','_new');</script>");
this opens a page that streams a pdf to the new browser window
basically with the following code ( I know stuff is missing here, but that doesn't really mater for the question)
byte[] pdfbytes = Convert.FromBase64String(rapportB64);
Response.ClearContent();
Response.ClearHeaders();
Response.Buffer = true;
Response.ContentType = GetContentType(format);
string header = GetContentDispostionHeader(fileName, format, type);
Response.AddHeader("Content-Disposition", header);
Response.BinaryWrite(pdfbytes);
Response.End();
Okay this code works !
Just not in IE6 and IE7 when using HTTPS
When using IE6 with HTTPS it results in a save-as dialog (not a pdf that opens in a browser)
When using IE7 with HTTPS it results in a blank screen
When using Firefox it works just fine
If I simulate the extra server side processing in the page_load to put the required data in the session and replace the button with a link that opens the same pdf generating page in a new window, the code works.
For the actual application it is not an option to get the required data before the button is clicked.
So I would really like to get the following code to work
string page = Request.ApplicationPath + "/ApkRapportPage.aspx";
Response.Write("<script language=\"javascript\">window.open('" + page + "','_new');</script>");
Questions:
Does anybody know why this code doesn't work in IE6 and IE7 when using HTTPS ?
What is needed to get the code to work ?
Extra info:
I tried not using response.write but
just a javascript window.open behind
the button, this has the same effect
when googling for pdf streaming, you can find a lot of people having
trouble with this, mostly they set
header lengths or other properties or
static file compression flags in IIS.
I am pretty confident I tried them
all.
Adobe acrobat reader settings, browser settings or any other client
side settings don't seem to be the
problem. Tested on different
machines, with http works, with https
it doesn't.
Switching between https and http might have something to do with this,
but when I set IE to tell me when I
am switching, no switching seems to
occur during testing.
When replacing the window.open part with a response.redirect then the code also works, just not in a new window
Any help would be greatly appreciated !
As requested the headers, as shown by Fiddler:
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Thu, 05 Mar 2009 14:18:36 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Content-Disposition: Inline;filename=APKrapport.pdf
Cache-Control: private
Content-Type: application/pdf; charset=utf-8
Content-Length: 28307
Getting attachments to open the way you want has everything to do with the headers you send. If you locate to an .aspx page that you want to act as a dynamic PDF resource these HTTP headers become increasingly important.
This website states a number of reasons why it might not work in IE.
Set the content-type of the response to "application/pdf", ex. response.setContentType("application/pdf");
Add a dummy parameter on the end of the url, like:
http://x.y.z/DoGenCompStmt?filename=dummy.pdf
because IE ignores content-types, so you need to give it a hint, and the ".pdf" extension is an easy way.
Set the "content-length" on the response, otherwise the Acrobat Reader plugin may not work properly, ex. response.setContentLength(bos.size());
An additional thing that seems to help some IE browsers is to also have : response.setHeader("Content-Disposition", "inline;filename=somepdf.pdf");
EDIT: since you already tried all of the above i can only point you to the rfc for content disposition which to my knowledge is the only way to tell a browser how to deal with binary content.
EDIT: what would really help is to see the HTTP Headers it currently returns when you try to open the pdf in the browser. Fiddler does a great job at catching traffic
You'd be better off using a generic handler (.ASHX) to serve this sort of content, rather than trying to force a web-page to serve content other than HTML.
After a lot of trial and error I found a working solution, still not sure why the other code doesn't work.
This code works:
StringBuilder js = new StringBuilder("<script language=\"javascript\">");
js.Append("_window = window.open(\"\",'_new');");
js.Append("_window.document.open(\"application/pdf\");");
js.Append("_window.location.href = \"ApkRapportPage.aspx\";");
js.Append("_window.document.close();");
js.Append("</script>");
Response.Write(js.ToString());
Must have something to do with the mime type.
It has a problem though. When IE is set to show when you switch between HTTP and HTTPS this code will give that message twice. The following code doesn't switch but causes the page load of ApkRapportPage to be fired twice.
StringBuilder js = new StringBuilder("<script language=\"javascript\">");
js.Append("_window = window.open(\"ApkRapportPage.aspx\",'_new');");
js.Append("_window.document.open(\"application/pdf\");");
js.Append("_window.location.href = \"ApkRapportPage.aspx\";");
js.Append("_window.document.close();");
js.Append("</script>");
Response.Write(js.ToString());
If you are getting a blank page when trying to view a PDF inline in the IE7 browser and you are using Acrobat version 6. Update your Acrobat version to resolve problem.
Note that this problem is unrelated to HTTPS, the same problem (and the same fix) applies for HTTP.
The fix works because the problem with IE is that it doesn't display PDF in a script-opened window if the PDF is loaded at once. (Unknown why, but this is the core of the problem, and the fix.)
I notice that your returned content-type is hosed
"Content-Type: application/pdf; charset=utf-8"
When you stream the content to the aspx page ensure that you set the
Response.charset = ""

How do I get the current location of an iframe?

I have built a basic data entry application allowing users to browse external content in iframe and enter data quickly from the same page. One of the data variables is the URL.
Ideally I would like to be able to load the iframes current url into a textbox with javascript. I realize now that this is not going to happen due to security issues.
Has anyone done anything on the server side? or know of any .Net browser in browser controls. The ultimate goal is to just give the user an easy method of extracting the url of the page they are viewing in the iframe It doesn't necessarily HAVE to be an iframe, a browser in the browser would be ideal.
Thanks,
Adam
I did some tests in Firefox 3 comparing the value of .src and .documentWindow.location.href in an iframe. (Note: The documentWindow is called contentDocument in Chrome, so instead of .documentWindow.location.href in Chrome it will be .contentDocument.location.href.)
src is always the last URL that was loaded in the iframe without user interaction. I.e., it contains the first value for the URL, or the last value you set up with Javascript from the containing window doing:
document.getElementById("myiframe").src = 'http://www.google.com/';
If the user navigates inside the iframe, you can't anymore access the value of the URL using src. In the previous example, if the user goes away from www.google.com and you do:
alert(document.getElementById("myiframe").src);
You will still get "http://www.google.com".
documentWindow.location.href is only available if the iframe contains a page in the same domain as the containing window, but if it's available it always contains the right value for the URL, even if the user navigates in the iframe.
If you try to access documentWindow.location.href (or anything under documentWindow) and the iframe is in a page that doesn't belong to the domain of the containing window, it will raise an exception:
document.getElementById("myiframe").src = 'http://www.google.com/';
alert(document.getElementById("myiframe").documentWindow.location.href);
Error: Permission denied to get property Location.href
I have not tested any other browser.
Hope it helps!
document.getElementById('iframeID').contentWindow.location.href
You can't access cross-domain iframe location at all.
I use this.
var iframe = parent.document.getElementById("theiframe");
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
var currentFrame = innerDoc.location.href;
HTA works like a normal windows application.
You write HTML code, and save it as an .hta file.
However, there are, at least, one drawback: The browser can't open an .hta file; it's handled as a normal .exe program. So, if you place a link to an .hta onto your web page, it will open a download dialog, asking of you want to open or save the HTA file. If its not a problem for you, you can click "Open" and it will open a new window (that have no toolbars, so no Back button, neither address bar, neither menubar).
I needed to do something very similar to what you want, but instead of iframes, I used a real frameset.
The main page need to be a .hta file; the other should be a normal .htm page (or .php or whatever).
Here's an example of a HTA page with 2 frames, where the top one have a button and a text field, that contains the second frame URL; the button updates the field:
frameset.hta
<html>
<head>
<title>HTA Example</title>
<HTA:APPLICATION id="frames" border="thin" caption="yes" icon="http://www.google.com/favicon.ico" showintaskbar="yes" singleinstance="no" sysmenu="yes" navigable="yes" contextmenu="no" innerborder="no" scroll="auto" scrollflat="yes" selection="yes" windowstate="normal"></HTA:APPLICATION>
</head>
<frameset rows="60px, *">
<frame src="topo.htm" name="topo" id="topo" application="yes" />
<frame src="http://www.google.com" name="conteudo" id="conteudo" application="yes" />
</frameset>
</html>
There's an HTA:APPLICATION tag that sets some properties to the file; it's good to have, but it isn't a must.
You NEED to place an application="yes" at the frames' tags. It says they belongs to the program too and should have access to all data (if you don't, the frames will still show the error you had before).
topo.htm
<html>
<head>
<title>Topo</title>
<script type="text/javascript">
function copia_url() {
campo.value = parent.conteudo.location;
}
</script>
</head>
<body style="background: lightBlue;" onload="copia_url()">
<input type="button" value="Copiar URL" onclick="copia_url()" />
<input type="text" size="120" id="campo" />
</body>
</html>
You should notice that I didn't used any getElement function to fetch the field; on HTA file, all elements that have an ID becomes instantly an object
I hope this help you, and others that get to this question. It solved my problem, that looks like to be the same as you have.
You can found more information here: http://www.irt.org/articles/js191/index.htm
Enjoy =]
I like your server side idea, even if my proposed implementation of it sounds a little bit ghetto.
You could set the .innerHTML of the iframe to the HTML contents you grab server side. Depending on how you grab this, you will have to pay attention to relative versus absolute paths.
Plus, depending on how the page you are grabbing interacts with other pages, this could totally not work (cookies being set for the page you are grabbing won't work across domains, maybe state is being tracked in Javascript... Lots of reasons this might not work.)
I don't believe that tracking the current state of the page you are trying to mirror is theoretically possible, but I'm not sure. The site could track all sorts of things server side, you won't have access to this state. Imagine the case where on a page load a variable is set to a random value server-side, how would you capture this state?
Do these ideas help with anything?
-Brian J. Stinar-
Does this help?
http://www.quirksmode.org/js/iframe.html
I only tested this in firefox, but if you have something like this:
<iframe name='myframe' id='myframe' src='http://www.google.com'></iframe>
You can get its address by using:
document.getElementById('myframe').src
Not sure if I understood your question correctly but anyways :)
You can use Ra-Ajax and have an iframe wrapped inside e.g. a Window control. Though in general terms I don't encourage people to use iframes (for anything)
Another alternative is to load the HTML on the server and send it directly into the Window as the content of a Label or something. Check out how this Ajax RSS parser is loading the RSS items in the source which can be downloaded here (Open Source - LGPL)
(Disclaimer; I work with Ra-Ajax...)
Ok, so in this application, there is an iframe in which the user is supplied with links or some capacity that allows that iframe to browse to some external site. You are then looking to capture the URL to which the user has browsed.
Something to keep in mind. Since the URL is to an external source, you will be limited in how much you can interact with this iframe via javascript (or an client side access for that matter), this is known as browser cross-domain security, as apparently you have discovered. There are clever work arounds, as presented here Cross-domain, cross-frame Javascript, although I do not think this work around applies in this case.
About all you can access is the location, as you need.
I would suggest making the code presented more resilitant and less error prone. Try browsing the web sometime with IE or FF configured to show javascript errors. You will be surprised just how many javascript errors are thrown, largely because there is a lot of error prone javascript out there, which just continues to proliferate.
This solution assumes that the iframe in question is the same "window" context where you are running the javascript. (Meaning, it is not embedded within another frame or iframe, in which case, the javascript code gets more involved, and you likely need to recursively search through the window hierarchy.)
<iframe name='frmExternal' id='frmExternal' src='http://www.stackoverflow.com'></frame>
<input type='text' id='txtUrl' />
<input type='button' id='btnGetUrl' value='Get URL' onclick='GetIFrameUrl();' />
<script language='javascript' type='text/javascript'>
function GetIFrameUrl()
{
if (!document.getElementById)
{
return;
}
var frm = document.getElementById("frmExternal");
var txt = document.getElementById("txtUrl");
if (frm == null || txt == null)
{
// not great user feedback but slightly better than obnoxious script errors
alert("There was a problem with this page, please refresh.");
return;
}
txt.value = frm.src;
}
</script>
Hope this helps.
You can access the src property of the iframe but that will only give you the initially loaded URL. If the user is navigating around in the iframe via you'll need to use an HTA to solve the security problem.
http://msdn.microsoft.com/en-us/library/ms536474(VS.85).aspx
Check out the link, using an HTA and setting the "application" property of an iframe will allow you to access the document.href property and parse out all of the information you want, including DOM elements and their values if you so choose.

Resources