Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Exploring a Folder and its Subdirectories using ASP.NET MVC

0.00/5 (No votes)
7 Feb 2013 1  
This article shows how you can easily make hyperlinks for exploring a folder on server and its subdirectories and downloading the files, using ASP.NET MVC.

Demo

Introduction

I had about 3000 PDF, ZIP and JPG files in too many folders on my server and wanted to simply make hyperlinks for exploring them on server in my site template and users can download the files in folders. This tip will show how you can easily make hyperlinks for exploring a folder on server and its subdirectories and downloading the files, using ASP.NET MVC.

Using the Code

This demo uses a default ASP.NET MVC 4 project.

New MVC project

We need to add Explorer Controller and its Index View, add ExplorerModel.cs, some edit in RouteConfig.cs and also add "Folder" that contain the files and folders for exploring and downloading.

Solution Explorer

Explorer Model

First of all, we need a model. So we add ExplorerModel.cs to Models. This model contains three classes. You could add every property that you want the classes to contain. In this demo, we made some simple models.
A class for DirModel that contains a directory information.

public class DirModel
{
    public string DirName { get; set; }
    public DateTime DirAccessed { get; set; }
}

A class for FileModel that contains file information.

public class FileModel
{
    public string FileName { get; set; }
    public string FileSizeText { get; set; }
    public DateTime FileAccessed { get; set; }
}

A class for ExplorerModel that contains directories and files list.

public class ExplorerModel
{
    public List<DirModel> dirModelList;
    public List<FileModel> fileModelList;

    public ExplorerModel(List<DirModel> _dirModelList, List<FileModel> _fileModelList)
    {
        dirModelList = _dirModelList;
        fileModelList = _fileModelList;
    }
}

Explorer Controller

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using FolderExplorer.Models;
using System.IO;

namespace FolderExplorer.Controllers
{
    public class ExplorerController : Controller
    {
        //
        // GET: /Explorer/

        public ActionResult Index(string path)
        {
            string realPath;
            realPath = Server.MapPath("~/Folder/" + path);
            // or realPath = "FullPath of the folder on server" 

            if (System.IO.File.Exists(realPath))
            {
                //http://stackoverflow.com/questions/1176022/unknown-file-type-mime
                return base.File(realPath, "application/octet-stream");
            }
            else if (System.IO.Directory.Exists(realPath))
            {

                Uri url = Request.Url;
                //Every path needs to end with slash
                if (url.ToString().Last() != '/')
                {
                    Response.Redirect("/Explorer/" + path + "/");
                }

                List<FileModel> fileListModel = new List<FileModel>();

                List<DirModel> dirListModel = new List<DirModel>();

                IEnumerable<string> dirList = Directory.EnumerateDirectories(realPath);
                foreach (string dir in dirList)
                {
                    DirectoryInfo d = new DirectoryInfo(dir);

                    DirModel dirModel = new DirModel();

                    dirModel.DirName = Path.GetFileName(dir);
                    dirModel.DirAccessed = d.LastAccessTime;

                    dirListModel.Add(dirModel);
                }

                IEnumerable<string> fileList = Directory.EnumerateFiles(realPath);
                foreach (string file in fileList)
                {
                    FileInfo f = new FileInfo(file);

                    FileModel fileModel = new FileModel();

                    if (f.Extension.ToLower() != "php" && f.Extension.ToLower() != "aspx"
                        && f.Extension.ToLower() != "asp")
                    {
                        fileModel.FileName = Path.GetFileName(file);
                        fileModel.FileAccessed = f.LastAccessTime;
                        fileModel.FileSizeText = (f.Length < 1024) ? 
                                 f.Length.ToString() + " B" : f.Length / 1024 + " KB";

                        fileListModel.Add(fileModel);
                    }
                }

                ExplorerModel explorerModel = new ExplorerModel(dirListModel, fileListModel);

                return View(explorerModel);
            }
            else
            {
                return Content(path + " is not a valid file or directory.");
            }
        }
    }
}

As you can see, ExplorerController has only one action. Index action gets the path parameter.

public ActionResult Index(string path)

How can we use path as UrlParameter?
If we browse "http://localhost:45114/Explorer/", we will see the files and directories in "Folder" and if we browse "http://localhost:45114/Explorer/Test%20Folder%201/Folder1/", we will see the files and directories in "Folder\Test Folder 1\Folder1". Because everything after "Explorer/" is our path and path contains some slashes and maybe spaces, so we can use URL: "Explorer/{*path}" in Explorer routes.MapRoute. So we must add the code below to RouteConfig.cs. See this for custom routes and MVC URLs with slash in parameter.

routes.MapRoute(
    name: "Explorer",
    url: "Explorer/{*path}",
    defaults: new { controller = "Explorer",
                    action = "Index",
                    path = UrlParameter.Optional }
);

The following code will define the folder, that you want to use for exploring, you could use any method that you prefer to define this, like using Web.Config, Injection or ... It's not important. This code is just used for demo. See this for Server.MapPath.

string realPath;
realPath  = Server.MapPath("~/Folder/" + path);
// or realPath = "FullPath of the folder on server"

Now we will check if the realPath is a file that exists. If it exists, we will send the contents of file as the response by using "return base.File(realPath, "application/octet-stream")". See this for more information about File. We will use "application/octet-stream" as contentType (See this).

if (System.IO.File.Exists(realPath))
{
    return base.File(realPath, "application/octet-stream");
}

If realPath wasn't a file, then we check if it's a directory or not.

else if (System.IO.Directory.Exists(realPath))
{
.
.
.
    return View(explorerModel);
}
else
{
    return Content(path + " is not a valid file or directory.");
}

For using browser ability to correctly browse the folders, every path needs to end with slash. The following codes do these:

Uri url = Request.Url;

if (url.ToString().Last() != '/')
{
    Response.Redirect("/Explorer/" + path + "/");
}

Then we need to define the list that contains DirModels:

List<DirModel> dirListModel = new List<DirModel>();
IEnumerable<string> dirList = Directory.EnumerateDirectories(realPath);
foreach (string dir in dirList)
{
    DirectoryInfo d = new DirectoryInfo(dir);

    DirModel dirModel = new DirModel();

    dirModel.DirName = Path.GetFileName(dir);
    dirModel.DirAccessed = d.LastAccessTime;

    dirListModel.Add(dirModel);
}

Also, we need to define the list that contains FileModels:

List<FileModel> fileListModel = new List<FileModel>();
IEnumerable<string> fileList = Directory.EnumerateFiles(realPath);
foreach (string file in fileList)
{
    FileInfo f = new FileInfo(file);

    FileModel fileModel = new FileModel();

    //if file extension was php or aspx or asp we will skip them
    if (f.Extension.ToLower() != "php" && f.Extension.ToLower() != "aspx"
        && f.Extension.ToLower() != "asp")
    {
        fileModel.FileName = Path.GetFileName(file);
        fileModel.FileAccessed = f.LastAccessTime;
        fileModel.FileSizeText =
        (f.Length < 1024) ? f.Length.ToString() + " B" : f.Length / 1024 + " KB";

        fileListModel.Add(fileModel);
    }
}

Finally, we return explorerModel to Explorer Index View.

ExplorerModel explorerModel = new ExplorerModel(dirListModel, fileListModel);

return View(explorerModel);

Explorer Index View

The description included in code:

@{
    ViewBag.Title = "Folder Explorer";
}
@{Uri uri = Request.Url;}

@*Show the current directory name using page URL. *@
<h2>@Server.UrlDecode(uri.Segments.Last())</h2>

@*If we were in root folder then don't show the up one level image. *@
@if (uri.AbsolutePath.ToLower() != "/explorer/")
{
    @*Making a URL to going up one level. *@
    <a title="Parent"

        href="@uri.AbsoluteUri.Remove(uri.AbsoluteUri.Length - uri.Segments.Last().Length)">
        <img src="http://www.codeproject.com/Content/up.png" 

         alt="Up" style="width: 20px; height: 20px; border: none" />
    </a>
}
<ul>
    @*Listing the directories *@
    @foreach (FolderExplorer.Models.DirModel dir in Model.dirModelList)
    {
        <li>
            <img src="http://www.codeproject.com/Content/folder.png" 

             alt="Folder Logo" align="top" style="width: 20px;
                height: 20px; border: none" />
            <a href="@dir.DirName/" title="@dir.DirName">@dir.DirName</a> 
            . . . . . . @dir.DirAccessed
        </li>
    }
    @*Listing the files *@
    @foreach (FolderExplorer.Models.FileModel file in Model.fileModelList)
    {
        <li><a href="@(uri.AbsolutePath + file.FileName)" 

        title="@file.FileName" target="_blank">
            @file.FileName</a>. . . . . . @file.FileSizeText
            . . . . . . @file.FileAccessed
        </li>
    }
</ul>

Related Tip

You can find the .NET Core version here.

Summary

This demo worked for me and it's serving the users. Hope it helps you too. Please don't forget to mark your votes, suggestions and feedback to improve the quality of this tip.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here