Skip to content

Instantly share code, notes, and snippets.

@nagasudhirpulla
Last active January 13, 2024 14:26
Show Gist options
  • Save nagasudhirpulla/c9b0fc8974aac99aa664be17b32edf7b to your computer and use it in GitHub Desktop.
Save nagasudhirpulla/c9b0fc8974aac99aa664be17b32edf7b to your computer and use it in GitHub Desktop.
Directory Browsing with sorting and additional columns in IIS

Directory browsing with sorting in IIS

  • Place the Files.aspx and Files.aspx.cs files in a folder which needs to be served as directory browsing in IIS
  • Make Files.aspx as the default document for the website in IIS
  • Files can be downloaded via static files IIS feature. Hence, enable the static content and ASP.NET latest version in "Turn Windows features on or off"
  • Request Filtering in IIS can be used for additional security measures like limiting file extensions, file size, url size etc.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Files.aspx.cs" Inherits="Files.FilesPage" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="Files" %>
<!DOCTYPE html>
<html>
<head>
<title>Contents of <%= path %></title>
<style type="text/css">
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
p {
font-family: verdana;
font-size: 10pt;
}
h2 {
font-family: verdana;
}
td, th {
font-family: verdana;
font-size: 10pt;
padding-left: 1em;
}
th {
text-align: left;
text-decoration: underline;
}
</style>
</head>
<body>
<h2>
<asp:HyperLink runat="server" ID="NavigateUpLink">[To Parent Directory]</asp:HyperLink>
<%= path %>
</h2>
<hr />
<table>
<tr>
<th>Name</th>
<th>Last Modified</th>
<th>Size (KB)</th>
<th>Extension</th>
<th>Type</th>
</tr>
<% foreach (DirectoryListingEntry fItem in listing)
{ %>
<tr>
<td>
<% if (fItem.FileSystemInfo is DirectoryInfo)
{%>
<a href="?path=<%=fItem.VirtualPath%>"><%=fItem.Filename%></a>
<%}
else
{%>
<a href="<%=fItem.VirtualPath%>" target="_blank"><%=fItem.Filename%></a>
<%}%>
</td>
<td><%= fItem.FileSystemInfo.LastWriteTime.ToString("yyyy-MMM-dd HH:mm")%></td>
<td><%= GetFileSizeString(fItem.FileSystemInfo) %></td>
<td><%=fItem.FileSystemInfo.Extension %></td>
<td><%=(fItem.FileSystemInfo is DirectoryInfo)?"folder":"file" %></td>
</tr>
<% } %>
</table>
<hr />
<p>
<asp:Label runat="Server" ID="FileCount" />
</p>
<script>
// https://stackoverflow.com/questions/14267781/sorting-html-table-with-javascript
var getCellValue = function (tr, idx) { return tr.children[idx].innerText || tr.children[idx].textContent; }
var comparer = function (idx, asc) {
return function (a, b) {
return function (v1, v2) {
return v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2);
}(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
}
};
// setup table sorting by clicking column header
Array.prototype.slice.call(document.querySelectorAll('th')).forEach(function (th) {
th.addEventListener('click', function () {
var table = th.parentNode
while (table.tagName.toUpperCase() != 'TABLE') table = table.parentNode;
Array.prototype.slice.call(table.querySelectorAll('tr:nth-child(n+2)'))
.sort(comparer(Array.prototype.slice.call(th.parentNode.children).indexOf(th), this.asc = !this.asc))
.forEach(function (tr) { table.appendChild(tr) });
})
});
</script>
</body>
</html>
using System;
using System.IO;
using System.Web;
using System.Collections.Generic;
namespace Files
{
public partial class FilesPage : System.Web.UI.Page
{
public DirectoryListingEntryCollection listing = new DirectoryListingEntryCollection();
public string path = "/";
protected void Page_Load()
{
path = Request.QueryString["path"];
if (string.IsNullOrEmpty(path))
{
path = "/";
}
else
{
path = VirtualPathUtility.AppendTrailingSlash(path);
}
string sortBy = Request.QueryString["sortby"];
//
// Databind to the directory listing
//
DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath(path));
FileSystemInfo[] fiFiles = dirInfo.GetFileSystemInfos();
foreach (FileSystemInfo f in fiFiles)
{
if (f.Attributes.HasFlag(FileAttributes.Hidden)) { continue; }
DirectoryListingEntry e = new DirectoryListingEntry();
e.FileSystemInfo = f;
e.Filename = f.Name;
//e.Path = f.FullName;
e.VirtualPath = path + (path.EndsWith("/") ? "" : "/") + f.Name;
listing.Add(e);
}
if (listing == null)
{
throw new Exception("This page cannot be used without the DirectoryListing module");
}
//
// Handle sorting
//
if (string.IsNullOrEmpty(sortBy))
{
// set default sorting
sortBy = "daterev";
}
if (sortBy.Equals("name"))
{
listing.Sort(DirectoryListingEntry.CompareFileNames);
}
else if (sortBy.Equals("namerev"))
{
listing.Sort(DirectoryListingEntry.CompareFileNamesReverse);
}
else if (sortBy.Equals("date"))
{
listing.Sort(DirectoryListingEntry.CompareDatesModified);
}
else if (sortBy.Equals("daterev"))
{
listing.Sort(DirectoryListingEntry.CompareDatesModifiedReverse);
}
else if (sortBy.Equals("size"))
{
listing.Sort(DirectoryListingEntry.CompareFileSizes);
}
else if (sortBy.Equals("sizerev"))
{
listing.Sort(DirectoryListingEntry.CompareFileSizesReverse);
}
//
// Prepare the file counter label
//
FileCount.Text = listing.Count + " items";
//
//
// Parepare the parent path label
string parentPath = null;
if (path.Equals("/") || path.Equals(VirtualPathUtility.AppendTrailingSlash(HttpRuntime.AppDomainAppVirtualPath)))
{
// cannot exit above the site root or application root
parentPath = null;
}
else
{
parentPath = VirtualPathUtility.Combine(path, "..");
}
if (string.IsNullOrEmpty(parentPath))
{
NavigateUpLink.Visible = false;
NavigateUpLink.Enabled = false;
}
else
{
NavigateUpLink.NavigateUrl = "?path=" + parentPath;
}
}
public string GetFileSizeString(FileSystemInfo info)
{
if (info is FileInfo)
{
return string.Format("{0}", (int)(((FileInfo)info).Length * 10 / (double)1024) / (double)10);
}
else
{
return string.Empty;
}
}
}
public class DirectoryListingEntryCollection : List<DirectoryListingEntry>
{
}
public class DirectoryListingEntry
{
//public string Path;
public string VirtualPath;
public string Filename;
public FileSystemInfo FileSystemInfo;
internal static int CompareFileNames(DirectoryListingEntry x, DirectoryListingEntry y)
{
return x.Filename.CompareTo(y.Filename);
}
internal static int CompareFileNamesReverse(DirectoryListingEntry x, DirectoryListingEntry y)
{
return -1 * x.Filename.CompareTo(y.Filename);
}
internal static int CompareDatesModified(DirectoryListingEntry x, DirectoryListingEntry y)
{
return x.FileSystemInfo.LastWriteTime.CompareTo(y.FileSystemInfo.LastWriteTime);
}
internal static int CompareDatesModifiedReverse(DirectoryListingEntry x, DirectoryListingEntry y)
{
return -1 * x.FileSystemInfo.LastWriteTime.CompareTo(y.FileSystemInfo.LastWriteTime);
}
internal static int CompareFileSizes(DirectoryListingEntry x, DirectoryListingEntry y)
{
if (x.FileSystemInfo is DirectoryInfo)
{
return -1;
}
if (y.FileSystemInfo is DirectoryInfo)
{
return 1;
}
return ((FileInfo)x.FileSystemInfo).Length.CompareTo(((FileInfo)y.FileSystemInfo).Length);
}
internal static int CompareFileSizesReverse(DirectoryListingEntry x, DirectoryListingEntry y)
{
if (x.FileSystemInfo is DirectoryInfo)
{
return -1;
}
if (y.FileSystemInfo is DirectoryInfo)
{
return 1;
}
return -1 * ((FileInfo)x.FileSystemInfo).Length.CompareTo(((FileInfo)y.FileSystemInfo).Length);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment