Use ASP:TreeView as a Directory and File Browsing Tool

This post is about how to make a directory / file browser tool for your website using the ASP.NET TreeView control. Get the full source code at Github.

I like to centralize all downloadable files into one subfolder of the website to avoid having all of the PDFs, etc, spread out in different folders. This code is for a user control that you can drop into any page to allow for access to your files that a user can navigate just like a normal file system. A couple of the features:

  • By default it will recursively search the current directory (for the page the control is on) and all subdirectories. There is a public property called AltRelFilePath where you can specify any path you want to use.

  • It will find any web.configs in the directories and it will apply the authorization rules you have for that directory.

  • It won't show directories that have no valid files in it.

  • It only shows the file types you want to see.

In the version I use, I made custom folder graphics and do a switch on the file extension to show the appropriate image for the file type (like navigating in Windows Explorer). I took that out for simplicity, but if you want to see it and want the files, go to https://github.com/MikeSmithDev/MASFileViewer.

For the front-end of the user control:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="fileViewer.ascx.cs" Inherits="WebApplication1.Controls.fileViewer" %>
<div id="_files" runat="server">
    <asp:TreeView ID="_tree" CollapseImageToolTip="Close Folder" ExpandImageToolTip="Open Folder" NodeWrap="true" ExpandDepth="1"  runat="server"></asp:TreeView>
</div>
<div id="_noFiles" visible="false" runat="server">
    <p>No files were found.</p>
</div>

And for the code-behind:

using System;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.UI.WebControls;

namespace WebApplication1.Controls
{
    public partial class fileViewer : System.Web.UI.UserControl
    {
        protected string _root;
        string[] _goodFileTypes = new string[] { ".gif", ".pdf", ".png", ".jpg", ".jpeg", ".doc", ".docx", ".xls", ".xlsx", ".txt", ".psd", ".eps", ".zip", ".ai", ".ppt", ".pptx" };
        private string _altRelFilePath;

        protected void Page_Load(object sender, EventArgs e)
        {
            CreateTree();
        }

        private void CreateTree()
        {
            _root = String.IsNullOrEmpty(_altRelFilePath) ? Server.MapPath(Request.Url.AbsolutePath) : Server.MapPath(_altRelFilePath);

            _tree.Nodes.Clear();
            var rootDirectory = String.IsNullOrEmpty(_altRelFilePath) ? new DirectoryInfo(Path.GetDirectoryName(_root)) : new DirectoryInfo(_root);

            TreeNode t = CreateDirectoryNode(rootDirectory);
            if (t != null)
            {
                _tree.Nodes.Add(t);
            }
            else
            {
                _noFiles.Visible = true;
                _files.Visible = false;
            }
        }

        private TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
        {
            TreeNode directoryNode = null;

            if (directoryInfo.Exists && CanViewFiles(directoryInfo))
            {
                directoryNode = new TreeNode(directoryInfo.Name) { Value = directoryInfo.FullName };

                directoryNode.NavigateUrl = "";
                directoryNode.SelectAction = TreeNodeSelectAction.Expand;

                foreach (var directory in directoryInfo.GetDirectories())
                {
                    TreeNode t = CreateDirectoryNode(directory);
                    if (t != null)
                    {
                        directoryNode.ChildNodes.Add(t);
                    }
                }

                foreach (var file in directoryInfo.GetFiles().Where(a => _goodFileTypes.Contains(a.Extension.ToLower())))
                {
                    var f = new TreeNode(file.Name);
                    f.ToolTip = "Download this file";
                    f.Text = f.Text + FileLength(file.Length);
                    f.NavigateUrl = RelativePath(file.FullName);
                    f.Target = "_blank";
                    directoryNode.ChildNodes.Add(f);
                }

                directoryNode = directoryNode.ChildNodes.Count > 0 ? directoryNode : null;
            }

            return directoryNode;
        }

        private string RelativePath(string fullName)
        {
            return "/" + fullName.Replace(Server.MapPath("~/"), String.Empty).Replace(@"\", "/");
        }

        private bool CanViewFiles(DirectoryInfo dir)
        {
            var config = WebConfigurationManager.OpenWebConfiguration(RelativePath(dir.FullName));
            if (config != null && config.HasFile)
            {
                var section = config.GetSection("system.web/authorization") as AuthorizationSection;
                if (section != null)
                {
                    foreach (AuthorizationRule rule in section.Rules)
                    {
                        if (rule.Action == AuthorizationRuleAction.Allow)
                        {
                            foreach (string role in rule.Roles)
                            {
                                if (HttpContext.Current.User.IsInRole(role))
                                {
                                    return true;
                                }
                            }

                            foreach (string user in rule.Users)
                            {
                                if (HttpContext.Current.User.Identity.Name == user)
                                {
                                    return true;
                                }
                            }
                        }
                    }
                    return false;
                }
            }
            return true;
        }

        private string FileLength(long fileSize)
        {
            return fileSize <= 999999 ? String.Format(" {0}{1}", (Math.Round((fileSize / 1024f), 2)).ToString(), " KB") :
                String.Format(" {0}{1}", (Math.Round((fileSize / 1024000f), 2)).ToString(), " MB)");
        }

        public string AltRelFilePath
        {
            get { return _altRelFilePath; }
            set { _altRelFilePath = value; }
        }
    }
}

To use it, you just put the control in the page. First, register the user control:

<%@ Register TagName="FileViewer" TagPrefix="uc" Src="~/Controls/fileViewer.ascx" %>

and then use it:

<uc:FileViewer ID="_fileViewer" runat="server" />

or specify the AltRelFilePath:

<uc:FileViewer ID="_fileViewer" AltRelFilePath="~/Images/" runat="server" />

And if you want to lock-down a particular subfolder, just add a web.config to that folder, like:

<configuration>
    <system.web>
        <authorization>
          <allow roles="CoolGuys"/>
          <deny users="*"/>
        </authorization>
   </system.web>
</configuration>

That's it! Happy coding.