ASP.NET Custom directory browse handler

98 Views Asked by At

I have a WebForms application running on IIS Express.

I'm using directoryBrowse=enabled to let users access parts of the file structure in order to download and open files. When I access a public directory on the website, a standard IIS directory listing page is displayed with the directory contents as usual.

I would like to register a custom handler specifically for directory browsing to control what is displayed and how when browsing directories. I know how to register a handler for a specific file or file type, however I don't know how to register a handler for a directory (ideally the same handler for any directory globally).

2

There are 2 best solutions below

0
DELTA12 On BEST ANSWER

I have found an answer myself. Posting for any finders with similar questions.

It turns out that I can register a handler for path */:

<add name="directory-handler" type="DirectoryHandler" path="*/" verb="*"/>

The server will then use this handler for any request ending with '/', except existing pages through FriendlyUrls or valid configured routes, which means it will use this handler for any directories in the server file tree. Then I create a new IHttpHandler called DirectoryHandler:

public class DirectoryHandler : IHttpHandler
{
    public const string DirectoryBrowserPage = "/Browse/";
    public bool IsReusable { get { return true; } }

    public void ProcessRequest(HttpContext context)
    {
        context.Response.Redirect(DirectoryBrowserPage + context.Request.Path);
    }
}

This will redirect any requests pointing to a directory to mypage.com/Browse/[Request.Path] Then, I register a new route in RouteConfig.cs:

 public static class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            //Conflicting routes must be defined before friendlyurls are 
            routes.Add("Browse", new Route("Browse/{*path}", new GenericRouteHandler("~/Browse.aspx")));

            var settings = new FriendlyUrlSettings();
            settings.AutoRedirectMode = RedirectMode.Permanent;
            routes.EnableFriendlyUrls(settings);
        }
    }

Implement GenericRouteHandler:

public class GenericRouteHandler : IRouteHandler
{

    public GenericRouteHandler(string virtualPath)
    {
        this.VirtualPath = virtualPath;
    }

    public string VirtualPath { get; private set; }

    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var page = BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page)) as IHttpHandler;
        foreach (var urlParm in requestContext.RouteData.Values)
        {
            requestContext.HttpContext.Items[urlParm.Key] = urlParm.Value;
        }
        return page;
    }

}

Finally, I create the Browse page itself, where I can access the requested directory path via:

string path = HttpContext.Current.Items["path"] as string;

The rest is then just a matter of manually creating the views, permissions and behavior in the Browse page.

1
Albert D. Kallal On

Hum, would it not be better to turn off folder browsing, and then say offer your own UI that is web based?

I note the above, since this VAST improves security, allows un-limited customizing of the UI. And say would allow limiting of folders and files based on the user's logon.

And better yet, you can also use folders OTHER then the server, but not have to create and map virtual folders from the web server to those other servers.

This means, that for additional folders etc., you don't have change the web server configuration.

Say you drop in a tree view control to the web page.

Chose the image set as "windows xp file explore".

enter image description here

So, now we have this markup:

<asp:TreeView ID="TreeView1" runat="server" ImageSet="XPFileExplorer"
    NodeIndent="15" OnTreeNodeExpanded="TreeView1_TreeNodeExpanded1">
    <HoverNodeStyle Font-Underline="True" ForeColor="#6666AA" />
    <NodeStyle Font-Names="Tahoma" Font-Size="8pt" ForeColor="Black"
        HorizontalPadding="2px" NodeSpacing="0px" VerticalPadding="2px" />
    <ParentNodeStyle Font-Bold="False" />
    <SelectedNodeStyle BackColor="#B5B5B5" Font-Underline="False"
        HorizontalPadding="0px" VerticalPadding="0px" />
</asp:TreeView>

So, code behind to "browse" folders is not a lot of code, but you can of course introduce restrictions on file types, and base the folder (limits) on the user's logon. So, say this code: (it is not even recursive, and recursion is not required).

Dim sRoot As String = "c:\SERVER01"

Public Class MyFolder
    Public MyFiles As FileInfo()
    Public MyFolders As DirectoryInfo()
End Class

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        lblFolder.Text = sRoot
        Dim MyFiles As MyFolder = GetFiles(sRoot)
        LoadTreeFiles(sRoot, MyFiles, "", Nothing)
    End If

End Sub


Public Function GetFiles(sRootFolder As String) As MyFolder

    Dim MyDir As New DirectoryInfo(sRootFolder)
    Dim cMyFolder As New MyFolder

    cMyFolder.MyFolders = MyDir.GetDirectories("*.*", SearchOption.TopDirectoryOnly)
    cMyFolder.MyFiles = MyDir.GetFiles("*.*", SearchOption.TopDirectoryOnly)

    Return cMyFolder

End Function


Sub LoadTreeFiles(fRootL As String,
                  lParent As MyFolder,
                  sParentID As String,
                  tTreeNode As TreeNode)

    ' add folders if any
    For Each sFolder As DirectoryInfo In lParent.MyFolders
        Dim child As New TreeNode
        child.Text = sFolder.Name
        child.Value = sFolder.FullName
        child.Expanded = False
        child.PopulateOnDemand = True
        child.ShowCheckBox = False

        If sParentID = "" Then
            TreeView1.Nodes.Add(child)
        Else
            tTreeNode.ChildNodes.Add(child)
        End If
    Next
    ' now any files
    For Each sFile As FileInfo In lParent.MyFiles

        Dim child As New TreeNode
        child.Text = sFile.Name
        child.Value = sFile.FullName
        child.Expanded = False
        child.ShowCheckBox = True
        child.PopulateOnDemand = False

        If sParentID = "" Then
            TreeView1.Nodes.Add(child)
        Else
            tTreeNode.ChildNodes.Add(child)
        End If
    Next

End Sub

Protected Sub TreeView1_TreeNodeExpanded1(sender As Object, e As TreeNodeEventArgs) Handles TreeView1.TreeNodeExpanded

    Dim child As TreeNode = e.Node
    Dim dtChild As MyFolder = GetFiles(child.Value)

    LoadTreeFiles(child.Value, dtChild, child.Text, child)

End Sub

So, now the web page shows:

enter image description here

So, it is not clear if you need/want a custom handler, but only that of building some kind of UI with say a tree view control, and building your own file browse system as per above. Since I only load each folder “on demand”, then the speed of above is very fast, and even for a system with a large and deep folder hierarchy.

The above has check boxes for multiple file selecting, but you could have a click on a file download. And the above design allows you to add additional UI options such as "select all this folder" or whatever.