【ASP.NET Core】Access local files
Tags: aspnetcore, csharp
Published: 2020-08-26 13:04:25

## Intro
This time, I access local files with ASP.NET Core.

* Make static files accessable from outside
* Get structures of directories
* Open PDF file in web browser
* Open movies with Razor

### Environments
* ASP.NET Core ver.3.1.302

## Make static files accessible from outside
To access static files for example CSS, JavaScript, and etc, I add codes in Startup Configure.

#### Startup.cs
```csharp
...
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            // make files what are in "wwwroot" directory accessible
            app.UseStaticFiles();

            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
...
```

If I put "Book1.xlsx" into the "wwwroot" directory, I can open it by "localhost:5000/Book1.xlsx".

### Use other directories
I also can make accessible other directories.

```csharp
...
    app.UseStaticFiles();
    app.UseStaticFiles(new StaticFileOptions {
        FileProvider = new PhysicalFileProvider(@"C:\Users\example\Pictures\ImageSample"),
        RequestPath = "/img"
    });
...
```

If I put "Book1.xlsx" into the "ImageSample" directory, I can open it by "localhost:5000/img/Book1.xlsx".

## Get structures of directories
I want to get structures of directory.
So I use "PhysicalFileProvider" again.

#### FilePath.cs
```csharp
using System.Collections.Generic;

namespace FileAccesses
{
    public struct FilePath
    {
        public string Name { get; set; }
        public string ParentPath { get; set; }
        public bool Directory { get; set; }
        public FileType FileType { get; set; }
        public List<FilePath> Children { get; set; }
    }
}
```
#### FileType.cs
```csharp
namespace FileAccesses
{
    public enum FileType
    {
        Directory = 0,
        Pdf,
        Movie,
        Others,
    }
}
```
#### FileMapGenerator.cs
```csharp
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.FileProviders;

namespace FileAccesses
{
    public static class FileMapGenerator
    {
        public static FilePath GetPaths(string rootDirectory)
        {
            if (Directory.Exists(rootDirectory) == false)
            {
                throw new ArgumentException("Directory was not found");
            }
            using(var provider = new PhysicalFileProvider(rootDirectory))
            {
                var rootInfo = new DirectoryInfo(rootDirectory);   
                var path = new FilePath
                {
                    Name = rootInfo.Name,
                    ParentPath = "",
                    Directory = true,
                    FileType = FileType.Directory,
                    Children = new List<FilePath>(),
                };
                foreach(var content in provider.GetDirectoryContents(string.Empty))
                {
                    path.Children.Add(GetChild(provider, content, ""));
                }
                return path;   
            }
        }
        private static FilePath GetChild(PhysicalFileProvider provider,
            IFileInfo fileInfo, string parentDirectoryName)
        {
            var path = $"{parentDirectoryName}{fileInfo.Name}/";
            var newPath = new FilePath
            {
                Name = fileInfo.Name,
                ParentPath = parentDirectoryName,                
            };
            if (fileInfo.IsDirectory)
            {
                newPath.Directory = true;
                newPath.FileType = FileType.Directory;
                newPath.Children = new List<FilePath>();
                foreach(var content in provider.GetDirectoryContents(path))
                {
                    newPath.Children.Add(GetChild(provider, content, path));
                }
            }
            else
            {
                newPath.FileType = GetFileType(fileInfo);
            }
            return newPath;
        }
        private static FileType GetFileType(IFileInfo fileInfo)
        {
            var extension = Path.GetExtension(fileInfo.PhysicalPath);
            if(string.IsNullOrEmpty(extension))
            {
                return FileType.Others;
            }
            switch(extension)
            {
                case ".pdf":
                    return FileType.Pdf;
                case ".mp4":
                case ".m4a":
                    return FileType.Movie;
                default:
                    return FileType.Others;
            }
        }
    }
}
```

## Open PDF file in web browser
When a request from web browser comes, I return a PDF file and open directly.

#### FileController.cs
```csharp
using System.IO;
using FileAccesses;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;

namespace Controllers
{
    public class FileController: Controller
    {
        private readonly ILogger<FileController> _logger;
        private readonly IConfiguration _config;
        private readonly IFileAccessService _fileAccess;
        public FileController(IFileAccessService fileAccess,
            IConfiguration config,
            ILogger<FileController> logger)
        {
            _logger = logger;
            _config = config;
            _fileAccess = fileAccess;
        }
...
        [Route("/Files/Pdf")]
        public IActionResult GetPdf(string fileName, string directory = "")
        {
            using (var provider = new PhysicalFileProvider(Path.Combine(_config["BasePath"], directory)))
            {
                var stream = provider.GetFileInfo(fileName).CreateReadStream();
                // To avoid opening the file in web brower,
                // I can add a file name as the third argument.
                return File(stream, "application/pdf");
            }
        }
    }
}
```

## Open movies with Razor

#### FileController.cs
```csharp
...
    [Route("/Files/Movies")]
    public IActionResult GetMovie(string fileName, string directory = "")
    {
        _logger.LogDebug("HelloMovies");
        var fullPath = Path.Combine(_config["BasePath"], directory);
        using (var provider = new PhysicalFileProvider(fullPath))
        {
            var stream = provider.GetFileInfo(fileName).CreateReadStream();
            return File(stream, "video/mp4");
        }
    }
    [Route("/Pages/Movies")]
    public IActionResult GetMovePage(string fileName, string directory = "")
    {
        var url = $"/Files/Movies?fileName={fileName}";
        if (string.IsNullOrEmpty(directory) == false)
        {
            url += $"&directory={directory}";
        }
        ViewData["url"] = url;

        return View("./Views/MoviePage.cshtml");
    }
...
```

#### MoviePage.cshtml
```csharp
@{
    var url = ViewData["url"];
}
<video controls width="500">
    <source src="@url" type="video/mp4">
</video>
```

## Resources
* [File Providers in ASP.NET Core | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/file-providers?view=aspnetcore-3.1)
* [Static files in ASP.NET Core | Microsoft Docs](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-3.1)