File protection is a common requirement when building Umbraco
applications (or any ASP.NET app for that matter). In fact Dirk De
Grave is currently working on a project called Protected Media that could
eventually provide this functionality in a package.
While building NCEExam.com, I used a different approach to
solve this problem. While I am not sure this is the best way to
accomplish file protection, it is very flexible and requires
no configuration in IIS. If you have ever worked with
DotNetNuke (first off, I'm sorry) you may recognize this.
First, simply add the file extension .resources to the end of
any file you wish to protect. You can do this manually before
uploading the file, or create a custom upload datatype to handle
this for you. The .resources file extension is already mapped to
the .NET runtime in IIS and, unlike .aspx, it is never served to
the client.
Next, create a document type and add a generic property to
it using the Upload datatype. You can leave the template
empty. Now, use this document type to upload files anywhere in your
content section.
You will need a user control to handle the file download. I
have the following method in my user control to handle this:
private void ServeFile(string FileName)
{
string strFileName = Server.MapPath(FileName);
string strFileId = strFileName.ToString().Replace(".resources", "");
string strFileExtension = Path.GetExtension(strFileId);
FileInfo fInfo = new FileInfo(strFileName);
Response.AddHeader("Content-Length", fInfo.Length.ToString());
switch (strFileExtension)
{
case ".pdf":
Response.ContentType = "application/pdf";
break;
case ".zip":
Response.ContentType = "application/zip";
break;
}
Response.AppendHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(strFileId));
Response.Clear();
Response.TransmitFile(strFileName);
Response.Flush();
Response.End();
}
Gather the file url from the generic property you created
earlier and pass it to the ServeFile method (FileName).
Next, strip off the .resources extension. Then, just set the
content length and content type and transmit the file using
Response.TransmitFile. You could easily extend the switch statement
to handle any number of content types or even add a new generic
property to your document type to store it.
Lastly, create a macro to serve this user control and slap it on
the empty template you created earlier. Then, simply use the
url of the document in the Content section (via Content
Picker or manually) to serve the file. You could even add
protection to the document for added security, but it is not
required.
One drawback to this method is that every file you upload will
have a document in the Content section. This is not a big deal, but
something worth noting.