<

Save as - for any file type

Published on
12,469 Points
6,169 Views
3 Endorsements
Last Modified:
Approved
Community Pick
When developing different types of ASP.NET applications I often face a requirement to let user download different types of files. They vary from logs in *.txt files or manuals/instructions in *.pdf files to charts in *.jpg files or reports in *.xls files. In most cases these files are generated at run-time or stored in a folder not directly accessible to user through URL.
As you know clicking on a link referencing e.g. *.txt file opens this file in browser window. Sometimes this behavior is not very comfortable for user when he/she desires to save file for later use.

This article will show you how to set up your application and links in your pages so user would be provided with Save As& dialog when clicking on such link.

Note: I use Visual Studio 2008 and C# language in this article and in a demo application available to download at the end of the article.

1. Create folder for you files


Create a folder where you will put files user could download. If files should not be accessible directly by URL to user App_Data folder (or subfolder in App_Data folder) would be a good choice because content from App_Data folder is not served to user.

To create a folder:
  1. In Visual Studio right-click on project name in solution explorer
  2. Choose New Folder
  3. Type a desired name of a folder. (I will use Files in this article.)
Create new folder
By default App_Data folder is automatically created when you create a new Web Site. If not (or you deleted one):
  1. In Visual Studio right-click on project name in solution explorer
  2. Choose Add ASP.NET Folder > App_Data.
Create App_Data folderFolder will be created and named for you.

2. Put files in created folder


Put any files you want to server to user in a newly created folder.

3. Create a HTTP handler to serve files.


From MSDN:

An ASP.NET HTTP handler is the process (frequently referred to as the "endpoint") that runs in response to a request made to an ASP.NET Web application. The most common handler is an ASP.NET page handler that processes .aspx files. When users request an .aspx file, the request is processed by the page through the page handler. You can create your own HTTP handlers that render custom output to the browser.
Basically HTTP handlers are special types of ASP.NET files where you provide content to user by manipulating HttpResponse object. Though the same functionality can be achieved with regular aspx page in this scenario HTTP handler is more suitable because it HTTP handlers are more lightweight and it takes less time for ASP.NET engine to process them.

To create HTTP handler:
  1. In Visual Studio right-click on project name in solution explorer
  2. Choose Add New Item&
  3. In open dialog choose Generic Handler from templates list
  4. Type desired handler's name in Name textbox (I will use "FileDownload.ashx" in this article)
  5. Click Add button
  Create HTTP handler
Note: handler name will be used in links on pages so make sure you give your handler a meaningful name

4. Make your handler work for you and users of your application


To do this you will have to implement two members of IHttpHandler interface. Let's start from easy one.

::: IsReusable property :::
From MSDN:

The IsReusable property specifies whether the IHttpHandlerFactory object (the object that actually calls the appropriate handler) can put the handler in a pool and reuse it to increase performance. If the handler cannot be pooled, the factory must create a new instance of the handler every time that the handler is needed.

public bool IsReusable
{
	get
	{
		return false;
	}
}

Open in new window


By default when you create a HTTP handler this property returns false. As handler we are creating is not resource intensive we could leave it as is. I've read forums where people complain that returning true has a negative impact on handler performance. I've tried returning true in my handlers but did not notice any effect so I always do return false;.

::: ProcessRequest method :::
From MSDN:

The ProcessRequest method is responsible for processing individual HTTP requests. In this method, you write the code that produces the output for the handler.
HTTP handlers have access to the application context. This includes the requesting user's identity (if known), application state, and session information. When an HTTP handler is requested, ASP.NET calls the ProcessRequest method of the appropriate handler. The code that you write in the handler's ProcessRequest method creates a response, which is sent back to the requesting browser.

As everything said is quite clear let's proceed further. HTTP handlers (I mean *.ashx files) are requested by browsers and support query strings as well. We are going to use query string to know witch file to serve.

//...
// Add necessary namespace to the top
// as we are working with file system
using System.IO;

Open in new window


public void ProcessRequest(HttpContext context)
{
	// You should validate query string here to make sure
	// it contains necessary information

	if (context.Request.QueryString.Count <= 0)
	{
		// could redirect to error page here
	}

	string file = context.Request.QueryString["FileName"];

	if (string.IsNullOrEmpty(file))
	{
		// could redirect to error page here
	}


	// Combine file name with folder name
	string filePath = context.Server.MapPath(string.Concat("~/Files/" + file));

	// Check if requested file exists
	if (!File.Exists(filePath))
	{
		// could redirect to error page here
	}

	// Always nice to know you're working with clear response object
	// just in case
	context.Response.Clear();

	// This is the heart of your functionality. Browser read response's content type
	// and decide whether they should show Save As.. dialog or show response in
	// in it's window. Special value application/save forces browser to show Save As... dialog
	context.Response.ContentType = "application/save";

	// Browser use this to detect name of a file to be downloaded
	context.Response.AddHeader("Content-Disposition", "attachment; filename=" + file);

	// Add file itself to response
	context.Response.WriteFile(filePath);

	// Flush our rendered response to browser
	context.Response.Flush();

	// We are done
	context.Response.End();

}

Open in new window


5. Links to files


As we have finished setting up our handler let's proceed to links.
Suppose we have a file named template.txt in our Files folder and we want to provide user with link so he/she could download that file by clicking on this link.
You can use either ASP.NET Hyperlink control or standard HTML <a> element to create link. The only difference is that ASP.NET Hyperlink control accepts application relative URLs (e.g."~/Files/template.txt") and standard HTML <a> elements do not.

<asp:HyperLink runat="server" NavigateUrl="~/FileDownload.ashx?FileName=template.txt" Text="Download template" />
<br />
<a href="FileDownload.ashx?FileName=template.txt">Download template</a>

Open in new window


Clicking on link like this user will be provided with "Save As&" dialog to save file instead of showing in browser window.

This is it. Our goal achieved.
This is just a simple sample. You can develop a more advances handlers where you pass some ID of database record to handler and it outputs some report in *.pdf file or chart in *.jpg file or& depends on requirements and needs.

In a demo application I attached to article you will find more extensive scenarios of FileDownload HTTP handler. EE does not allow uploading most of ASP.NET files (even if they are compressed in zip file) so I added a .txt extension to every file.
Download here:Demo.zip

This is my first article ever so please forgive me if did not like something about style of writing.
Your comments and criticism are very welcome.

Resources:
  HTTP Handlers and HTTP Modules Overview
  http://msdn.microsoft.com/en-us/library/bb398986.aspx

  Walkthrough: Creating a Synchronous HTTP Handler
  http://msdn.microsoft.com/en-us/library/ms228090.aspx

  IHttpHandler Interface
  http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.aspx
3
Comment
Author:Ramuncikas
2 Comments
 

Expert Comment

by:analogue
This is the best explanation of asp.net filedownload I've seen - after months of searching this worked for me within 15 minutes. Absolutely 1st class.

A HUGE THANKS for this post.
0
 
LVL 14

Author Comment

by:Ramuncikas
You're welcome
I'm very glad it helped you

R
0

Featured Post

Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

Join & Write a Comment

In response to a need for security and privacy, and to continue fostering an environment members can turn to for support, solutions, and education, Experts Exchange has created anonymous question capabilities. This new feature is available to our Pr…
From store locators to asset tracking and route optimization, learn how leading companies are using Google Maps APIs throughout the customer journey to increase checkout conversions, boost user engagement, and optimize order fulfillment. Powered …

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month