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

Exploring a Folder and its Sub-directories using ASP.NET Core MVC

0.00/5 (No votes)
8 Nov 2018 1  
This article shows how you can easily make hyperlinks for exploring a folder on server and its sub-directories and downloading the files, using ASP.NET Core MVC.

Background

This tip is .NET-Core version of "Exploring a folder and its subdirectories using ASP.NET MVC".

Using the Code

This demo uses a default ASP.NET Core web application.

We need to add Explorer Controller and its Index View, add ExplorerModel.cs, some edit in Startup.cs and also add "Folder" that contains the files and folders for explore and download.

Explorer Model

First of all, we need some models. So we add ExplorerModel.cs to Models. This file contains three classes. You could add any property that you want to the classes. In this demo, we made some simple models.

A class for DirModel that contains 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 and few other properties as below:

public class ExplorerModel
    {
        public List<DirModel> DirModelList;
        public List<FileModel> FileModelList;

        public String FolderName;
        public String ParentFolderName;
        public String URL;

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

Injection in Explorer Controller

To be able to use ContentRootPath and HttpContext.Request, we need 2 injections in ExplorerController as below:

public class ExplorerController : Controller
 {
     private readonly IHostingEnvironment _hostingEnvironment;
     private readonly IHttpContextAccessor _httpContextAccessor;

     public ExplorerController(IHostingEnvironment hostingEnvironment,
                               IHttpContextAccessor httpContextAccessor)
     {
         _hostingEnvironment = hostingEnvironment;
         _httpContextAccessor = httpContextAccessor;
     }
     .
     .
     .

Index Action in Explorer Controller

public IActionResult Index(string path)
{
    var folderPath = _hostingEnvironment.ContentRootPath + "\\Folder\\";
    // or folderPath = "FullPath of the folder on server" 

    var realPath = folderPath + path;

    if (System.IO.File.Exists(realPath))
    {

        var fileBytes = System.IO.File.ReadAllBytes(realPath);

        //http://stackoverflow.com/questions/1176022/unknown-file-type-mime
        return File(fileBytes, "application/force-download");

    }
    else if (Directory.Exists(realPath))
    {
        List<DirModel> dirListModel = MapDirs(realPath);

        List<FileModel> fileListModel = MapFiles(realPath);

        ExplorerModel explorerModel = new ExplorerModel(dirListModel, fileListModel);

        //For using browser ability to correctly browsing the folders,
        //Every path needs to end with slash
        if (realPath.Last() != '/' && realPath.Last() != "\\")
        { explorerModel.URL = "/Explorer/" + path + "/"; }
        else
        { explorerModel.URL = "/Explorer/" + path; }

        var request = _httpContextAccessor.HttpContext.Request;

        UriBuilder uriBuilder = new UriBuilder
        { Path = request.Path.ToString() };
                
        //Show the current directory name using page URL.
        explorerModel.FolderName = WebUtility.UrlDecode(uriBuilder.Uri.Segments.Last());

        //Making a URL to going up one level. 
        Uri uri = new Uri(uriBuilder.Uri.AbsoluteUri.Remove
                            (uriBuilder.Uri.AbsoluteUri.Length - 
                             uriBuilder.Uri.Segments.Last().Length));

        explorerModel.ParentFolderName = uri.AbsolutePath;

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

ExplorerController has only one action. Index action gets the path parameter.

public IActionResult Index(string path)

How we can 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 Startup.cs.

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

The following code will define the folder, that you want to use it 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.

var folderPath = _hostingEnvironment.ContentRootPath + "\\Folder\\";
// or folderPath = "FullPath of the folder on server" 

var realPath = folderPath + path;

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 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))
{
    var fileBytes = System.IO.File.ReadAllBytes(realPath);

    //http://stackoverflow.com/questions/1176022/unknown-file-type-mime
    return File(fileBytes, "application/force-download");
}

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 browsing the folders, every path needs to end with slash. The following codes do these.

//For using browser ability to correctly browsing the folders,
//Every path needs to end with slash
if (realPath.Last() != '/' && realPath.Last() != "\\")
{ explorerModel.URL = "/Explorer/" + path + "/"; }
else
{ explorerModel.URL = "/Explorer/" + path; }

Then we need to map the list that contains DirModels:

private List<DirModel> MapDirs(String realPath)
{
    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
        {
            DirName = Path.GetFileName(dir),
            DirAccessed = d.LastAccessTime
        };

        dirListModel.Add(dirModel);
    }

    return dirListModel;
}

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

private List<FileModel> MapFiles(String realPath)
{
    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 (f.Extension.ToLower() != "php" && f.Extension.ToLower() != "aspx"
            && f.Extension.ToLower() != "asp" && f.Extension.ToLower() != "exe")
        {
            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);
        }
    }

    return fileListModel;
}

Finally, we provide the needed values for the explorerModel.ParentFolderName and explorerModel.FolderName, then return explorerModel to Explorer Index View.

UriBuilder uriBuilder = new UriBuilder
{ Path = request.Path.ToString() };
                
//Getting the current directory name using page URL.
explorerModel.FolderName = WebUtility.UrlDecode(uriBuilder.Uri.Segments.Last());

//Making a URL to going up one level. 
Uri uri = new Uri(uriBuilder.Uri.AbsoluteUri.Remove
                    (uriBuilder.Uri.AbsoluteUri.Length 
                     - uriBuilder.Uri.Segments.Last().Length));

explorerModel.ParentFolderName = uri.AbsolutePath;

return View(explorerModel);

Explorer Index View

The description included in code:

@{
    ViewBag.Title = "Folder Explorer";
}

<h2>@Model.FolderName</h2>

@if (Model.URL.ToLower() != "/explorer/")
{
    <a title="Parent" href="@Model.ParentFolderName">
        <img src="~/images/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="~/images/folder.png" alt="Folder Logo" align="top" style="width: 20px;
                height: 20px; border: none" />
            <a href="@(Model.URL + 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="@(Model.URL + file.FileName)"

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

Related Tip

You can find the .NET MVC 4.0 version in this tip.

Summary

Hope it helps. 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