Often when working with web applications it is necessary to secure access to documents or other user supplied resources. If you look online you will find a number of different recommendations on how to accomplish this. Some will recommend a HTTP Handler, some will recommend a simple ASPX, others will have other random ideas. Regardless of the actual implementation there is always a common area of mixed recommendation, once you have validated that the user has the proper permissions to access the resource, how do you get the item to the user? In this post I'll discuss a new API that is publicly available in .NET 4.5 that helps with one problem area.
The Problem
Determining if the user has access to the resource in question is rarely the area that causes trouble. The problem comes with the process of serving the desired files to the user. When you let IIS handle the serving of a file it automatically sets the Content Type on the HTTP Response to match the proper type for the file, however, if you are sitting in the middle of this process, you have to handle this yourself.
Recommendation to Solve Issue
If you look into this issue, try googleing "Determining File MIME Types" or similar. You will find all kinds of recommendations. They will range from creating a custom look up process based on file extension, to weird PInvoke calls into windows, or even from the really crafty individuals a reflection call to an internal member of previous versions of the .NET framework.
In the end, there has never really been a good, consistent way to handle this. Often times if you are working with a limited subset of file types the switch statement solution will work, however, as new file types are added etc it becomes harder to manage.
New Solution
With .NET 4.5, there is a newly exposed class that can be used to solve this complicated process. System.Web.MimeMapping is a class that has existed for a while prior to .NET 4.5 but was "internal" to the framework and could not easily be called without using reflection. Now you can simply call a method with a file path and it will return the Content Type.
This makes it so that we can now use something as simple as the following to serve a secured document after validating that the user has permissions.
Response.Clear();
Response.ContentType =
System.Web.MimeMapping.GetMimeMapping(Server.MapPath(document.ServerDocumentPath));
Response.AddHeader("Content-Disposition",
"attachment; filename=" + document.UploadedDocumentName);
Response.WriteFile(Server.MapPath(document.ServerDocumentPath));
Response.End();
As you can see here, it is just 5 lines of code. In the first line of code we clear anything that might have already been written to the response. In the second line we call out to MimeMapping's GetMimeMapping method providing it the filepath to our document. The third line we are telling the browser that we want to force download the file and are specifying a custom file name. Then in the last two lines we write the file to the response and end.
The nice thing with this approach as you can see in the above example we can have a different ServerDocumentPath than our actual document name. This allows us to hide the files in a different manner and serve them up to users with a friendly name.
I hope this helps someone looking for a way to introduce a security process to file downloads. This .NET framework MimeType mapping is very helpful for this type of situation.