*************************************************
(NEW) Update - 2/1/09:
Clarified installation instructions (see post).
Fixed bugs:
 - Occasional icons missing / icons missing during heavy load due to MTA problems with SHGetFileInfo (http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=337530)
 - Directory listing template has broken icons in some configurations 
*************************************************
Update - 4/26/08:
IconHandler 2.0 released. Use IconHandler to build your own directory listing,
or any other app that needs file icons.

************************************************** 

Do you hate bland directory listing pages that most web servers have these days?  The Internet has gone through many evolutions, yet web directory listings somehow got left out to the point where sometimes they appear to predate the http protocol itself (gopher, anyone?).  Here is the default IIS7 directory listing:

Almost two years ago, this exact emotion led Bill Staples to write a sample directory listing module for our first set of early IIS7 demos.  This module read the directory contents of a url, and generated a nice-looking gallery view of the images in that directory.  It was a much needed improvement!

Since then, several other people on the team modified and re-wrote the module, adding visual bells and whistles and otherwise changing the way it looked.  Everyone thought it looked best their way.  The module grew and grew into a mess of c# code and HTML fragments, to the point where noone ever wanted to show the code for it, just how cool it made the site look.  For fun, here is a code excerpt from the original module:

                //write out links to paths leading up to directory

                Response.Write("<h3>g a l l e r y : ");

                    for (int i = 0; i<strpaths.Length-1;i++) {

                        strURL = strURL + strpaths[i] ;

                        Response.Write("<a href="" + strURL + "/" + "">" + strpaths[i] + "/" + "</a>");

                        strURL = strURL + "/";

                    }

                Response.Write("</h3>n");

I've always wanted to take the module, and rewrite it so that it provided complete separation of the module infrastructure / directory reading code, and the actual HTML content.  This way, a designer could go in and change the layout and the look and feel of the directory listing without having to change the code itself ... And since I try to stay away from actual website design as much as possible, this would give me all the pleasure of writing some server code and none of the pain of trying to make it look good.  That's the designer's job!

With that in mind, I wrote this directory listing module that uses an ASPX page as a template for generating the actual output, so the look and feel is entirely in the designers control.  The module simply provides the directory listing as a bindable collection of directory entries, each of which contains useful properties that can be used inside the the page to generate the UI.

In a nutshell, here is what the module does:

  1. Intercepts requests to "directory" urls within your application, like "http://example.com/files/"
  2. Reads the directory contents, and creates a collection of DirectoryListingEntry objects
  3. Stores this collection inside the HttpContext.Items collection
  4. Executes the configured template page, which databinds to the directory listing collection and produces the desired UI for your custom directory listing
  5. Hardcodes Absolutely No HTML content in the module ...

The sample page I wrote has a DataList control that I databind to the collection inside Page_Load():

void Page_Load()

{  

    DirectoryListingEntryCollection listing =         

Context.Items[DirectoryListingModule.DirectoryListingContextKey] as DirectoryListingEntryCollection;

   

    DirectoryListing.DataSource = listing;

    DirectoryListing.DataBind();

}

 

<asp:DataList id="DirectoryListing" runat="server">

    <ItemTemplate>

        <a href="<%# ((DirectoryListingEntry)Container.DataItem).VirtualPath  %>"><%# ((DirectoryListingEntry)

        Container.DataItem).Filename %></a>

    </ItemTemplate>

</asp:DataList>

On top of this, I threw in some sorting capabilities (The DirectoryListingEntry object provides a number of IComparer delegates that can be used to sort the collection on date modified, file size, and file name, but you can of course implement your own), and nice looking file icons using the IconHandler.  With minimal HTML design, here is what I got:

I want it!

You can view this app running live on my server here: http://mvolo.com/directorylisting/ (since I dont have VS installed on the server, ASPX shows with text icons). 

Download the sample app containing both the DirectoryListingModule, my simple template, and the IconHandler. 

Installation instructions:

IIS7:

  0.  Install ASP.NET if you havent already (DUH?)

  1.  Run the following from a command prompt (open it with the "run as Administrator" option):

  %windir%System32inetsrvappcmd set module DirectoryListingModule /lockItem:false

  (this is done to unlock the built-in DirectoryListingModule for removal in the application, so that it can be replaced with our custom one)

  2.  Create an application, and unzip the contents of the app into its root directory.  That's it!

IIS6:

  0.  Install ASP.NET if you havent already (DUH?)

  1.  Create an application, and configure ASP.NET 2.0 to be a wildcard mapping for it. 

  2.  Unzip the contents of the app into the root directory of your application, and you are good to go.

What else is there to do?

Right now, the module is only aware of the physical file system directory structure for the directory you are viewing.  So, if your directory has a virtual subdirectory that maps to a physical location somewhere else, it won't show up in the directory list.  For example, if your application http://example.com/myapp has a root in c:myapp, and you have a virtual directory http://example.com/myapp/files that points to c:files, you are not going to see "files" in the directory listing for /myapp.  To fix this, the directory listing module needs to be Virtual Path Provider aware, which will also have a bonus in being able to provide directory listings of sharepoint sites.  This is coming soon ...

Also, since I am sure you are a better designer then me, if you end up making a cool directory listing template you want to share, please post it here.  If you make the coolest one, there may even be a prize involved ...