Hello, I am looking for a very easy way for a user to view a word or pdf document from a webpage. On the webpage, I have user information, specifically, a filepath to a document stored on a file server that when a usert clicks a button or hyperlink, it will
open that document, read only, in a separate window. I've tried a couple of things but can't get around the "Download, save, abort" window that pops up on server.redirect and using a hyperlink button.
Can anyone avise me on a very easy way to achieve this?
thanks.
Put your mind first and your body will follow!
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
You can have the page just write it out. Let's say they send the request to your page like this:
"downloadfile.aspx?file=somefile.doc"
Now, in downloadfile.aspx, you need to set up things like this example (though you SHOULD check to ensure they are downloading from the directory you expect!):
void Page_Load ( object sender, EventArgs e )
string strRequest = Request.QueryString["file"]; //-- if something was passed to the file querystring
if ( strRequest != "" )
{
//get absolute path of the file
// the file is passed like a web address /images/myimage.jpg
string path = Server.MapPath(strRequest); //get file object as FileInfo
System.IO.FileInfo file = new System.IO.FileInfo(path); //-- if the file exists on the server
if ( file.Exists ) //set appropriate headers
{
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Response.AddHeader("Content-Length", file.Length.ToString());
Response.ContentType = "application/octet-stream";
// write file to browser
Response.WriteFile(file.FullName);
Response.End();
}
else
{
// if file does not exist
Response.Write("This file does not exist.");
}
}
else
{
//nothing in the URL as HTTP GET
Response.Write("Please provide a file to download.");
}
}
I worked with this briefly, but I noticed 2 problems with this approach,
1) - the downloadfile.aspx page opens, which I do not want an additional window for the user to close AND
2) - the File Download dialog box opens offering the user to save, open or cancel the word document. Which I do not want, I need it to just open up the document in another page.
It would be ideal for the user to click a button on a webpage and that would simply open word or adobe using an existing document, in a seperate window.
Hope this makes sense.
Thanks again!
Put your mind first and your body will follow!
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
Remove the "attachment; " portion of the "Content-Disposition" header and it should work. You should also send the proper mime type (text/html for HTML documents, for instance), but it is not always necessary and application/octet-stream basically lets
the browser figure it out. Testing on my own machine with various file types, it opened up the new window and either loaded the file in the window (text, HTML), or required me to open it with the Download dialog, which closed the window when I downloaded
the item. One case did not close the window, which was a PDF file using "application/octet-stream" but by providing "application/pdf" it was correctly opened in the window. I am running IE 7. Providing the mime type for the Office types (Excel's is "application/vnd.ms-excel"
I believe) did not seem to help, but I am running the beta for Office 2007, so that might be a security feature to not display them within the browser and it still closed the window.
Thanks for taking the time to create this detailed resolution. Everything functions as you had mentioned. FYI, if the document to view is a .pdf, I use the application/pdf oterwise I use application/Actet-stream.
I am now wondering if there is a way for these documents to be brought up in read-only, where the user cannot change and then resave the document.
Is there something I can set in the code behind of the DownLoadFile.aspx page or something I can add to the Response.AddHeader?
Thanks much for the assistance.
Put your mind first and your body will follow!
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
Yes, you can change the ReadOnly attribute of the file, but are you sure that this is necessary?
The users are downloading the file from the server, and they will not be able to change the file on the server unless they have access to replace that file themselves (such as through FTP).
It's not as though the users open the file, then click save and it overwrites the file on your server.
Anyway, if you just wanted to make the files ReadOnly, then you can set them to be ReadOnly before sending the files by adding "file.IsReadOnly = true;" before sending the file ("Response.WriteFile(file.FullName);"). Make sure that you set it back to false,
or it will stay Read Only (of course, you or the user can just go into the folder [that the file resides, or they download your file to] and right click -> Properties -> Uncheck Read-only to change it manually in Windows Explorer).
Picky
Marked as answer by whatacrazyworld on Jan 31, 2007 01:10 PM
Thanks Picky. FYI, I am an old cobol programmer still adjusting to the C# switch. Your detailed answers are very helpful. The more code examples I see the better.
The reason I want to set the readonly attribute is simple, it is easier for me to explain to the user that, Yes, the file is readonly, aposed to explaining why the readonly is not necessary because blah, blah, blah.......
Thanks for the help. Job well done!!!!!!!!!!!!!!!!!!
Put your mind first and your body will follow!
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
I'm working on a similar thing to what you're discussing here, I don't want to show a download dialog, I just want the file displayed in the browser. I've got it all working at the moment, but I must say I don't really understand this contentType or even
the attachHeader and content-disposition stuff. For example, I've used the octet-stream as the catch all because using octet-stream for pdf documents caused the adobe application to launch. Still no download dialog but it opens a new window (Adobe reader)
which I don't want. But using Application/pdf, works perfectly.
Is this because I don't specify an attach header as inline? As you can see from below, I try to identify the file type, but I don't think it's robust enough because clients may use many more file types.
Any thoughts/comments on this would be much appreciated.
Thanks
public void ProcessRequest(HttpContext context)
{
//context.Response.Write("Hello World");
String sFileName = "";
String sFullPath = String.Empty;
sFullPath = context.Request.QueryString["FullPath"];
if (sFullPath != null && sFullPath.Length > 4)
{
if (sFullPath.Contains(@"\"))
{
if (File.Exists(sFullPath))
{
FileInfo _file4View = new FileInfo(sFullPath);
context.Response.Buffer = false;
context.Response.Clear();
String sContentType = "";
switch (Path.GetExtension(sFullPath).ToLower())
{
case ".dwf":
sContentType = "Application/x-dwf";
break;
case ".pdf":
sContentType = "Application/pdf";
break;
case ".doc":
sContentType = "Application/vnd.ms-word";
break;
case ".ppt":
case ".pps":
sContentType = "Application/vnd.ms-powerpoint";
break;
case ".xls":
sContentType = "Application/vnd.ms-excel";
break;
default:
sContentType = "Application/octet-stream";
break;
}
context.Response.ContentType = sContentType;
MemoryStream _Stream = new MemoryStream();
//StreamWriter _writer = new StreamWriter(_Stream);
FileStream _fileStream = new FileStream(sFullPath, FileMode.Open, FileAccess.Read);
long fileLength = _fileStream.Length;
Byte[] _byte = new Byte[(int)fileLength];
_fileStream.Read(_byte, 0, (int)fileLength);
_fileStream.Close();
context.Response.BinaryWrite(_byte);
}
}
}
}
A few things jump out at me when looking at your code that do not really have to do with the download dialog.
You do not do very much path checking to see if the requested file's location is maybe a little too close on your root drive (luckily you will probably be protected by user rights, but that's not really guaranteed).
You declare and instantiate your FileInfo variable for the Extension property, but you never use it (you instead use a static method from System.IO.Path; both operate the same), which is fine, but you should get rid of it or use it.
You go to a lot of effort to write out your file, when you could just use "context.Response.WriteFile(sFullPath);" or "context.Response.WriteFile(_file4View.FullName);" instead of using all of the streams, and the byte array.
Ignoring the last point, I see that you store the file's length as a long value (appropriately since the property returns a long), but then you cast it twice into an integer. It's not a big deal by any means, but you might as well store it as an integer
in the first place to avoid two wasted casts right after it. Again, this is just me being, well,
picky.
As for the actual issue at hand, you don't need to add the "attachment;" part to the Content Disposition (similarly, you do not and should not add "inline;" to it, but you
could for certain files). You actually do not even need to add the Content Disposition, but I think it is helpful, especially for files that may not be opened inside of the browser (such as MS Word files in my case with Word 2007 Beta), in which case
it will suggest a filename for them. Using the headers kind of suggests dumping the use of Path.GetExtension(...) in favor of using _file4View.Extension because it will make it easier to get the file name (without the path) and the file's length easily.
Replace Path.Get..(...).ToLower() with _file4View.Extension.ToLower(), and you should probably rename your FileInfo variable to something a little more friendly (_file4View doesn't make much sense to me, to be honest).
// get a better FileInfo var name too
// and spit out a [hopefully] friendly file name
context.Response.AddHeader("Content-Disposition", "filename=" + _file4View.Name);
// give it the file length too
context.Response.AddHeader("Content-Length", _file4View.Length.ToString());
To better explain the HTTP Headers, I think it would be best to read up on them since I don't think I will do you any justice, and this is one of the best explanations of
Content-Length that I have found. It is very short, and very to-the-point. Long story short, is that if you know the length, then you should tell the client. The same site also
provides a nice explanation for
Content-Disposition, which is to basically use it to suggest a default filename when necessary.
whatacrazywo...
Member
68 Points
25 Posts
Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 29, 2007 02:24 PM|LINK
Hello, I am looking for a very easy way for a user to view a word or pdf document from a webpage. On the webpage, I have user information, specifically, a filepath to a document stored on a file server that when a usert clicks a button or hyperlink, it will open that document, read only, in a separate window. I've tried a couple of things but can't get around the "Download, save, abort" window that pops up on server.redirect and using a hyperlink button.
Can anyone avise me on a very easy way to achieve this?
thanks.
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
pickyh3d
Star
9696 Points
1955 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 29, 2007 04:07 PM|LINK
You can have the page just write it out. Let's say they send the request to your page like this:
Now, in downloadfile.aspx, you need to set up things like this example (though you SHOULD check to ensure they are downloading from the directory you expect!):
http://www.xefteri.com/articles/show.cfm?id=8
I forgot I was on the C# forum.
There is the example in C#.
whatacrazywo...
Member
68 Points
25 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 29, 2007 04:59 PM|LINK
Thanks for the reply!!!!
I worked with this briefly, but I noticed 2 problems with this approach,
1) - the downloadfile.aspx page opens, which I do not want an additional window for the user to close AND
2) - the File Download dialog box opens offering the user to save, open or cancel the word document. Which I do not want, I need it to just open up the document in another page.
It would be ideal for the user to click a button on a webpage and that would simply open word or adobe using an existing document, in a seperate window.
Hope this makes sense.
Thanks again!
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
pickyh3d
Star
9696 Points
1955 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 30, 2007 04:48 AM|LINK
Remove the "attachment; " portion of the "Content-Disposition" header and it should work. You should also send the proper mime type (text/html for HTML documents, for instance), but it is not always necessary and application/octet-stream basically lets the browser figure it out. Testing on my own machine with various file types, it opened up the new window and either loaded the file in the window (text, HTML), or required me to open it with the Download dialog, which closed the window when I downloaded the item. One case did not close the window, which was a PDF file using "application/octet-stream" but by providing "application/pdf" it was correctly opened in the window. I am running IE 7. Providing the mime type for the Office types (Excel's is "application/vnd.ms-excel" I believe) did not seem to help, but I am running the beta for Office 2007, so that might be a security feature to not display them within the browser and it still closed the window.
For the full list of "official" types: http://www.iana.org/assignments/media-types/
whatacrazywo...
Member
68 Points
25 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 30, 2007 06:50 PM|LINK
Thanks for taking the time to create this detailed resolution. Everything functions as you had mentioned. FYI, if the document to view is a .pdf, I use the application/pdf oterwise I use application/Actet-stream.
I am now wondering if there is a way for these documents to be brought up in read-only, where the user cannot change and then resave the document.
Is there something I can set in the code behind of the DownLoadFile.aspx page or something I can add to the Response.AddHeader?
Thanks much for the assistance.
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
pickyh3d
Star
9696 Points
1955 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 31, 2007 03:51 AM|LINK
Yes, you can change the ReadOnly attribute of the file, but are you sure that this is necessary?
The users are downloading the file from the server, and they will not be able to change the file on the server unless they have access to replace that file themselves (such as through FTP).
It's not as though the users open the file, then click save and it overwrites the file on your server.
Anyway, if you just wanted to make the files ReadOnly, then you can set them to be ReadOnly before sending the files by adding "file.IsReadOnly = true;" before sending the file ("Response.WriteFile(file.FullName);"). Make sure that you set it back to false, or it will stay Read Only (of course, you or the user can just go into the folder [that the file resides, or they download your file to] and right click -> Properties -> Uncheck Read-only to change it manually in Windows Explorer).
whatacrazywo...
Member
68 Points
25 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 31, 2007 01:10 PM|LINK
Thanks Picky. FYI, I am an old cobol programmer still adjusting to the C# switch. Your detailed answers are very helpful. The more code examples I see the better.
The reason I want to set the readonly attribute is simple, it is easier for me to explain to the user that, Yes, the file is readonly, aposed to explaining why the readonly is not necessary because blah, blah, blah.......
Thanks for the help. Job well done!!!!!!!!!!!!!!!!!!
A ship at port is safe but that is not what the ship was built for!
Courage is being afraid but saddling up anyway!
pickyh3d
Star
9696 Points
1955 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Jan 31, 2007 08:26 PM|LINK
You're welcome, and I am glad I could help.
Hopefully your transition to C# can be pretty painless.
reckface
Member
17 Points
13 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Feb 08, 2007 12:57 PM|LINK
Hi Picky
I'm working on a similar thing to what you're discussing here, I don't want to show a download dialog, I just want the file displayed in the browser. I've got it all working at the moment, but I must say I don't really understand this contentType or even the attachHeader and content-disposition stuff. For example, I've used the octet-stream as the catch all because using octet-stream for pdf documents caused the adobe application to launch. Still no download dialog but it opens a new window (Adobe reader) which I don't want. But using Application/pdf, works perfectly.
Is this because I don't specify an attach header as inline? As you can see from below, I try to identify the file type, but I don't think it's robust enough because clients may use many more file types.
Any thoughts/comments on this would be much appreciated.
Thanks
public void ProcessRequest(HttpContext context) { //context.Response.Write("Hello World"); String sFileName = ""; String sFullPath = String.Empty; sFullPath = context.Request.QueryString["FullPath"]; if (sFullPath != null && sFullPath.Length > 4) { if (sFullPath.Contains(@"\")) { if (File.Exists(sFullPath)) { FileInfo _file4View = new FileInfo(sFullPath); context.Response.Buffer = false; context.Response.Clear(); String sContentType = ""; switch (Path.GetExtension(sFullPath).ToLower()) { case ".dwf": sContentType = "Application/x-dwf"; break; case ".pdf": sContentType = "Application/pdf"; break; case ".doc": sContentType = "Application/vnd.ms-word"; break; case ".ppt": case ".pps": sContentType = "Application/vnd.ms-powerpoint"; break; case ".xls": sContentType = "Application/vnd.ms-excel"; break; default: sContentType = "Application/octet-stream"; break; } context.Response.ContentType = sContentType; MemoryStream _Stream = new MemoryStream(); //StreamWriter _writer = new StreamWriter(_Stream); FileStream _fileStream = new FileStream(sFullPath, FileMode.Open, FileAccess.Read); long fileLength = _fileStream.Length; Byte[] _byte = new Byte[(int)fileLength]; _fileStream.Read(_byte, 0, (int)fileLength); _fileStream.Close(); context.Response.BinaryWrite(_byte); } } } }pickyh3d
Star
9696 Points
1955 Posts
Re: Opening a Word or PDF file from a webpage. C#, VS2005, APS 2.0
Feb 09, 2007 05:33 AM|LINK
You do not do very much path checking to see if the requested file's location is maybe a little too close on your root drive (luckily you will probably be protected by user rights, but that's not really guaranteed).
You declare and instantiate your FileInfo variable for the Extension property, but you never use it (you instead use a static method from System.IO.Path; both operate the same), which is fine, but you should get rid of it or use it.
You go to a lot of effort to write out your file, when you could just use "context.Response.WriteFile(sFullPath);" or "context.Response.WriteFile(_file4View.FullName);" instead of using all of the streams, and the byte array.
Ignoring the last point, I see that you store the file's length as a long value (appropriately since the property returns a long), but then you cast it twice into an integer. It's not a big deal by any means, but you might as well store it as an integer in the first place to avoid two wasted casts right after it. Again, this is just me being, well, picky.
As for the actual issue at hand, you don't need to add the "attachment;" part to the Content Disposition (similarly, you do not and should not add "inline;" to it, but you could for certain files). You actually do not even need to add the Content Disposition, but I think it is helpful, especially for files that may not be opened inside of the browser (such as MS Word files in my case with Word 2007 Beta), in which case it will suggest a filename for them. Using the headers kind of suggests dumping the use of Path.GetExtension(...) in favor of using _file4View.Extension because it will make it easier to get the file name (without the path) and the file's length easily. Replace Path.Get..(...).ToLower() with _file4View.Extension.ToLower(), and you should probably rename your FileInfo variable to something a little more friendly (_file4View doesn't make much sense to me, to be honest).
To better explain the HTTP Headers, I think it would be best to read up on them since I don't think I will do you any justice, and this is one of the best explanations of Content-Length that I have found. It is very short, and very to-the-point. Long story short, is that if you know the length, then you should tell the client. The same site also provides a nice explanation for Content-Disposition, which is to basically use it to suggest a default filename when necessary.
I agree that both should be used.