- 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.
Last active
January 13, 2024 14:26
-
-
Save nagasudhirpulla/c9b0fc8974aac99aa664be17b32edf7b to your computer and use it in GitHub Desktop.
Directory Browsing with sorting and additional columns in IIS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%@ 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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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