Search code examples
asp.netiisiis-expresshttphandler

ASP.NET Custom directory browse handler


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).


Solution

  • 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.