ASP.NET Core의 파일 공급자File Providers in ASP.NET Core

작성자: Steve SmithBy Steve Smith

ASP.NET Core에서 파일 공급자를 사용하여 파일 시스템 액세스를 추상화합니다.ASP.NET Core abstracts file system access through the use of File Providers.

예제 코드 보기 및 다운로드(다운로드 방법)View or download sample code (how to download)

파일 공급자 추상화File Provider abstractions

파일 공급자는 파일 시스템에 대한 추상화로.File Providers are an abstraction over file systems. 기본 인터페이스는 IFileProvider입니다.The main interface is IFileProvider. IFileProvider는 파일 정보(IFileInfo)나 디렉터리 정보(IDirectoryContents)를 가져오고, 변경 알림을 설정(IChangeToken 을 사용) 하는 메서드를 노출합니다.IFileProvider exposes methods to get file information (IFileInfo), directory information (IDirectoryContents), and to set up change notifications (using an IChangeToken).

IFileInfo는 개별 파일 및 디렉터리에 대한 메서드와 속성을 제공합니다.IFileInfo provides methods and properties about individual files or directories. 두 가지 불리언 속성인 Exists 속성과 IsDirectory속성을 비롯해서 파일 이름(Name), 크기(Length, 바이트) 및 마지막 수정 날짜(LastModified)를 기술하는 속성들을 갖고 있습니다.It has two boolean properties, Exists and IsDirectory, as well as properties describing the file's Name, Length (in bytes), and LastModified date. CreateReadStream 메서드를 사용해서 파일을 읽을 수도 있습니다.You can read from the file using its CreateReadStream method.

파일 공급자 구현File Provider implementations

IFileProvider 의 구현으로 물리적 공급자, 임베디드 공급자 그리고 복합 공급자의 세 가지 공급자를 사용할 수 있습니다.Three implementations of IFileProvider are available: Physical, Embedded, and Composite. 물리적 공급자는 시스템의 실제 파일에 접근하기 위해서 사용됩니다.The physical provider is used to access the actual system's files. 그리고 임베디드 공급자는 어셈블리에 포함된 파일에 접근하기 위해서 사용됩니다.The embedded provider is used to access files embedded in assemblies. 마지막으로 복합 공급자는 하나 이상의 개별 공급자로부터 얻어진 파일 및 디렉터리에 대한 복합적인 접근을 지원하기 위해서 사용됩니다.The composite provider is used to provide combined access to files and directories from one or more other providers.

PhysicalFileProviderPhysicalFileProvider

PhysicalFileProvider 는 실제 파일 시스템에 대한 접근을 제공합니다.The PhysicalFileProvider provides access to the physical file system. System.IO.File 형식을 (물리적 공급자에 대해) 래핑하고, 특정 디렉터리와 그 하위 자식들에 대한 모든 경로를 대상 범위로 지정합니다.It wraps the System.IO.File type (for the physical provider), scoping all paths to a directory and its children. 이렇게 범위를 지정함으로써 특정 디렉터리 및 그 하위 자식들에 대한 접근만 허용해서 경계 외부의 파일 시스템에 대한 접근을 차단합니다.This scoping limits access to a certain directory and its children, preventing access to the file system outside of this boundary. 이 공급자의 인스턴스를 생성하려면 이 공급자를 대상으로 하는 모든 요청에 대해 기본 경로 역할을 하는 (그리고 해당 경로 외부에 대한 접근은 차단하는) 디렉터리 경로를 반드시 제공해야 합니다.When instantiating this provider, you must provide it with a directory path, which serves as the base path for all requests made to this provider (and which restricts access outside of this path). ASP.NET Core 응용 프로그램에서는 PhysicalFileProvider 공급자의 인스턴스를 직접 생성하거나, 컨트롤러 또는 서비스의 생성자에서 IFileProvider종속성 주입 을 통해서 를 요청할 수 있습니다.In an ASP.NET Core app, you can instantiate a PhysicalFileProvider provider directly, or you can request an IFileProvider in a Controller or service's constructor through dependency injection. 일반적으로 후자의 접근 방식이 보다 유연하고 테스트 가능한 솔루션을 만들어줍니다.The latter approach will typically yield a more flexible and testable solution.

다음 예제는 PhysicalFileProvider 를 생성하는 방법을 보여줍니다.The sample below shows how to create a PhysicalFileProvider.

IFileProvider provider = new PhysicalFileProvider(applicationRoot);
IDirectoryContents contents = provider.GetDirectoryContents(""); // the applicationRoot contents
IFileInfo fileInfo = provider.GetFileInfo("wwwroot/js/site.js"); // a file under applicationRoot

하위 경로를 지정해서 디렉터리의 내용을 반복 조회하거나 특정 파일의 정보를 가져올 수도 있습니다.You can iterate through its directory contents or get a specific file's information by providing a subpath.

컨트롤러에서 공급자를 사용하려면 공급자를 컨트롤러의 생성자 매개 변수로 지정한 다음, 전달받은 공급자 개체를 필드에 할당합니다.To request a provider from a controller, specify it in the controller's constructor and assign it to a local field. 그리고 액션 메서드에서는 이 로컬 인스턴스를 사용합니다.Use the local instance from your action methods:

public class HomeController : Controller
{
    private readonly IFileProvider _fileProvider;

    public HomeController(IFileProvider fileProvider)
    {
        _fileProvider = fileProvider;
    }

    public IActionResult Index()
    {
        var contents = _fileProvider.GetDirectoryContents("");
        return View(contents);
    }

그런 다음, 응용 프로그램의 Startup 클래스에서 공급자를 생성합니다.Then, create the provider in the app's Startup class:

using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;

namespace FileProviderSample
{
    public class Startup
    {
        private IHostingEnvironment _hostingEnvironment;
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();

            _hostingEnvironment = env;
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddMvc();

            var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
            var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
            var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);

            // choose one provider to use for the app and register it
            //services.AddSingleton<IFileProvider>(physicalProvider);
            //services.AddSingleton<IFileProvider>(embeddedProvider);
            services.AddSingleton<IFileProvider>(compositeProvider);
        }

다음 Index.cshtml 뷰는 전달된 IDirectoryContents 를 반복 조회합니다.In the Index.cshtml view, iterate through the IDirectoryContents provided:

@using Microsoft.Extensions.FileProviders
@model  IDirectoryContents

<h2>Folder Contents</h2>

<ul>
    @foreach (IFileInfo item in Model)
    {
        if (item.IsDirectory)
        {
            <li><strong>@item.Name</strong></li>
        }
        else
        {
            <li>@item.Name - @item.Length bytes</li>
        }
    }
</ul>

그 결과는 다음과 같습니다.The result:

파일 공급자 예제 응용 프로그램이 실제 파일 및 폴더의 목록을 출력합니다.

EmbeddedFileProviderEmbeddedFileProvider

EmbeddedFileProvider 는 어셈블리에 포함된 파일에 접근하기 위한 용도로 사용됩니다.The EmbeddedFileProvider is used to access files embedded in assemblies. .NET Core에서는 .csproj 파일의 <EmbeddedResource> 요소에 지정된 파일들이 어셈블리에 포함됩니다.In .NET Core, you embed files in an assembly with the <EmbeddedResource> element in the .csproj file:

<ItemGroup>
  <EmbeddedResource Include="Resource.txt;**\*.js" Exclude="bin\**;obj\**;**\*.xproj;packages\**;@(EmbeddedResource)" />
  <Content Update="wwwroot\**\*;Views\**\*;Areas\**\Views;appsettings.json;web.config">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
  </Content>
</ItemGroup>

어셈블리에 포함시킬 파일들을 지정할 때, Globbing 패턴 을 사용할 수 있습니다.You can use globbing patterns when specifying files to embed in the assembly. 이 패턴을 사용하면 하나 이상의 파일을 지정할 수 있습니다.These patterns can be used to match one or more files.

참고

실제로 프로젝트의 모든 .js 파일을 어셈블리에 포함시키는 일은 거의 없습니다. 위 예제는 단지 설명을 위한 것입니다.It's unlikely you would ever want to actually embed every .js file in your project in its assembly; the above sample is for demo purposes only.

EmbeddedFileProvider 를 생성할 때, 생성자에게 읽고자 하는 어셈블리를 전달해야 합니다.When creating an EmbeddedFileProvider, pass the assembly it will read to its constructor.

var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());

위의 코드 조각은 현재 실행 중인 어셈블리에 접근하는 EmbeddedFileProvider 를 생성하는 방법을 보여줍니다.The snippet above demonstrates how to create an EmbeddedFileProvider with access to the currently executing assembly.

앞의 예제 응용 프로그램을 EmbeddedFileProvider 를 사용하도록 업데이트하면 다음과 같은 결과가 출력됩니다.Updating the sample app to use an EmbeddedFileProvider results in the following output:

파일 공급자 예제 응용 프로그램이 임베디드 파일들의 목록을 출력합니다.

참고

어셈블리에 포함된 리소스는 디렉터리를 노출하지 않는 반면.Embedded resources don't expose directories. 대신, 리소스에 대한 경로(해당 네임스페이스를 통해)는 . 구분 기호를 사용하여 해당 파일 이름에서 포함됩니다.Rather, the path to the resource (via its namespace) is embedded in its filename using . separators.

EmbeddedFileProvider 생성자는 선택적 baseNamespace 매개 변수를 허용합니다.The EmbeddedFileProvider constructor accepts an optional baseNamespace parameter. 이를 지정하면 GetDirectoryContents에 대한 호출을 제공된 네임스페이스 아래의 해당 리소스로 범위를 지정합니다.Specifying this will scope calls to GetDirectoryContents to those resources under the provided namespace.

CompositeFileProviderCompositeFileProvider

CompositeFileProviderIFileProvider 의 인스턴스들을 결합해서 다수의 공급자를 이용한 파일 작업을 처리할 수 있는 단일 인터페이스를 제공합니다. The CompositeFileProvider combines IFileProvider instances, exposing a single interface for working with files from multiple providers. CompositeFileProvider 를 생성할 때는 생성자에 하나 이상의 IFileProvider 인스턴스를 전달합니다.When creating the CompositeFileProvider, you pass one or more IFileProvider instances to its constructor:

var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);

이전에 구성된 물리적 및 포함된 공급자 모두를 포함하는 CompositeFileProvider를 사용하도록 샘플 앱을 업데이트하면 다음 출력과 같은 결과가 발생합니다.Updating the sample app to use a CompositeFileProvider that includes both the physical and embedded providers configured previously, results in the following output:

물리적 파일 및 폴더와 포함된 파일을 나열하는 파일 공급자 샘플 응용 프로그램

변경 내용 감시하기Watching for changes

IFileProviderWatch 메서드를 이용하면 여러 파일 및 디렉터리의 변경 사항을 감지할 수 있습니다.The IFileProvider Watch method provides a way to watch one or more files or directories for changes. 이 메서드는 Globbing 패턴을 이용해서 복수의 파일을 지정할 수 있는 경로 문자열을 전달받고 IChangeToken을 반환합니다.This method accepts a path string, which can use globbing patterns to specify multiple files, and returns an IChangeToken. 이 토큰은 변경 여부 확인에 사용할 수 있는 HasChanged 속성과, 지정된 경로 문자열에서 변경 내용이 감지되면 호출되는 RegisterChangeCallback 메서드를 제공합니다.This token exposes a HasChanged property that can be inspected, and a RegisterChangeCallback method that's called when changes are detected to the specified path string. 각 변경 토큰은 단일 변경에 대한 응답으로 자신과 연결된 콜백만 호출한다는 점에 주의하시기 바랍니다.Note that each change token only calls its associated callback in response to a single change. 모니터링을 지속적으로 수행하기 위해서는 다음 예제처럼 TaskCompletionSource를 활용하거나 변경 사항에 대한 응답에서 다시 IChangeToken 인스턴스를 생성해야 합니다.To enable constant monitoring, you can use a TaskCompletionSource as shown below, or re-create IChangeToken instances in response to changes.

이 문서 샘플에서 콘솔 응용 프로그램은 텍스트 파일이 수정될 때마다 메시지를 표시하도록 구성됩니다.In this article's sample, a console application is configured to display a message whenever a text file is modified:

private static PhysicalFileProvider _fileProvider = 
    new PhysicalFileProvider(Directory.GetCurrentDirectory());

public static void Main(string[] args)
{
    Console.WriteLine("Monitoring quotes.txt for changes (Ctrl-c to quit)...");

    while (true)
    {
        MainAsync().GetAwaiter().GetResult();
    }
}

private static async Task MainAsync()
{
    IChangeToken token = _fileProvider.Watch("quotes.txt");
    var tcs = new TaskCompletionSource<object>();

    token.RegisterChangeCallback(state => 
        ((TaskCompletionSource<object>)state).TrySetResult(null), tcs);

    await tcs.Task.ConfigureAwait(false);

    Console.WriteLine("quotes.txt changed");
}

파일을 여러 번 저장한 후 결과는 다음과 같습니다.The result, after saving the file several times:

dotnet 실행을 실행한 후 명령 창은 변경 내용에 대한 quotes.txt 파일을 모니터링하는 응용 프로그램과 파일이 5번 변경된 것을 보여 줍니다.

참고

Docker 컨테이너나 네트워크 공유 같은 일부 파일 시스템은 변경 알림을 안정적으로 전송할 수 없습니다.Some file systems, such as Docker containers and network shares, may not reliably send change notifications. 그러나 DOTNET_USE_POLLINGFILEWATCHER 환경 변수를 1이나 true로 설정하면 파일 시스템이 4초마다 폴링됩니다.Set the DOTNET_USE_POLLINGFILEWATCHER environment variable to 1 or true to poll the file system for changes every 4 seconds.

Globbing 패턴Globbing patterns

파일 시스템 경로는 Globbing 패턴이라고도 부르는 와일드 카드 패턴을 사용합니다.File system paths use wildcard patterns called globbing patterns. 이 단순 패턴을 이용해서 파일 그룹을 지정할 수 있습니다.These simple patterns can be used to specify groups of files. 두 개의 와일드 카드 문자는 ***입니다.The two wildcard characters are * and **.

*

현재 폴더 수준의 모든 항목, 모든 파일명 또는 모든 파일 확장자를 찾습니다Matches anything at the current folder level, or any filename, or any file extension. 파일 경로의 /. 문자에 의해서 일치가 중단됩니다.Matches are terminated by / and . characters in the file path.

**

여러 디렉터리 수준에서 모든 것을 일치시킵니다.Matches anything across multiple directory levels. 디렉터리 계층 구조 내의 여러 파일과 일치시키는 데 재귀적으로 사용될 수 있습니다.Can be used to recursively match many files within a directory hierarchy.

Globbing 패턴 예제Globbing pattern examples

directory/file.txt

특정 디렉터리에 있는 특정 파일을 일치시킵니다.Matches a specific file in a specific directory.

directory/*.txt

특정 디렉터리에서 .txt 확장명으로 모든 파일을 일치시킵니다.Matches all files with .txt extension in a specific directory.

directory/*/bower.json

directory 디렉터리보다 정확히 한 수준 아래의 디렉터리에서 모든 bower.json 파일을 일치시킵니다.Matches all bower.json files in directories exactly one level below the directory directory.

directory/**/*.txt

directory 디렉터리 아래의 모든 곳에서 찾은 모든 파일을 .txt 확장명으로 일치시킵니다.Matches all files with .txt extension found anywhere under the directory directory.

ASP.NET Core에서 파일 공급자 사용File Provider usage in ASP.NET Core

ASP.NET Core는 다양한 부분에서 파일 공급자를 활용합니다.Several parts of ASP.NET Core utilize file providers. 예를 들어,IHostingEnvironment는 응용 프로그램의 콘텐츠 루트와 웹 루트를 IFileProvider 형식으로 노출합니다.IHostingEnvironment exposes the app's content root and web root as IFileProvider types. 정적 파일 미들웨어는 파일 공급자를 이용해서 정적 파일을 찾습니다.The static files middleware uses file providers to locate static files. Razor는 뷰를 찾기 위해 IFileProvider를 빈번히 사용합니다.Razor makes heavy use of IFileProvider in locating views. Dotnet의 게시 기능은 파일 공급자와 Globbing 패턴을 사용해서 게시해야 할 파일들을 지정합니다.Dotnet's publish functionality uses file providers and globbing patterns to specify which files should be published.

앱에서 사용에 대한 권장 사항Recommendations for use in apps

ASP.NET Core 앱에 파일 시스템 액세스가 필요한 경우 종속성 주입을 통해 IFileProvider의 인스턴스를 요청한 다음, 이 샘플에 나와 있는 것처럼 해당 메서드를 사용하여 액세스를 수행할 수 있습니다.If your ASP.NET Core app requires file system access, you can request an instance of IFileProvider through dependency injection, and then use its methods to perform the access, as shown in this sample. 이를 통해 앱이 시작하고 앱이 인스턴스화하는 구현 형식의 수를 줄일 때 공급자를 한 번 구성할 수 있습니다.This allows you to configure the provider once, when the app starts up, and reduces the number of implementation types your app instantiates.