ASP.NET Core 파일 공급자

등록일시: 2017-09-04 08:00,  수정일시: 2017-09-15 01:36
조회수: 81
본 번역문서는 ASP.NET Core 기술을 널리 알리고자 하는 개인적인 취지로 번역되어 제공되는 문서로, 원문을 비롯한 모든 저작권은 마이크로소프트사에 있습니다. 마이크로소프트사의 요청이 있을 경우, 언제라도 게시가 중단될 수 있습니다. 본 번역문서에는 오역이 포함되어 있을 수 있으며 주석도 번역자 개인의 견해일뿐입니다. 마이크로소프트사는 본 문서의 번역된 내용에 대해 일체의 보장을 하지 않습니다. 번역이 완료된 뒤에도 제품이 업그레이드 되거나 기능이 변경됨에 따라 원문도 변경되거나 보완되었을 수 있으므로 참고하시기 바랍니다.
본문에서는 ASP.NET Core의 세 가지 파일 공급자인 물리적 공급자, 임베디드 공급자 및 복합 공급자에 관해서 살펴봅니다.

ASP.NET Core는 파일 공급자를 이용해서 파일 시스템에 대한 접근을 추상화합니다.

예제 코드 살펴보기 및 다운로드

파일 공급자 추상

파일 공급자는 파일 시스템에 대한 추상화로, 그 중 가장 핵심적인 인터페이스는 IFileProvider입니다. IFileProvider는 파일의 정보(IFileInfo)를 얻거나 디렉터리의 정보(IDirectoryContents)를 얻고, 변경 알림을 (IChangeToken을 이용해서) 설정하기 위한 메서드를 노출합니다.

IFileInfo는 개별 파일이나 디렉터리에 관한 메서드 및 속성을 제공합니다. 두 가지 부울 속성, ExistsIsDirectory를 비롯해서 파일의 이름 (Name), 크기 (Length, 바이트), 마지막 수정 날짜 (LastModified) 및 파일의 물리적 경로를 (PhysicalPath) 기술하는 속성들을 갖고 있습니다. 또한 CreateReadStream 메서드를 사용해서 파일을 읽을 수도 있습니다.

파일 공급자 구현

IFileProvider의 세 가지 구현, 즉 물리적 공급자, 임베디드 공급자 그리고 복합 공급자를 사용할 수 있습니다. 물리적 공급자는 시스템의 실제 파일에 접근하기 위해서 사용됩니다. 그리고 임베디드 공급자는 어셈블리에 포함된 파일에 접근하기 위해서 사용됩니다. 마지막으로 복합 공급자는 하나 이상의 개별 공급자로부터 얻어진 파일 및 디렉터리에 대한 복합적인 접근을 지원하기 위해서 사용됩니다.

PhysicalFileProvider

PhysicalFileProvider는 물리적 파일 시스템에 대한 접근을 제공합니다. System.IO.File 형식을 (물리적 공급자에 대한) 래핑하고, 특정 디렉터리와 그 하위 자식들에 대한 모든 경로를 대상 범위로 지정합니다. 이 범위 지정은 특정 디렉터리 및 그 하위에 대한 접근만을 허용함으로써 경계 외부의 파일 시스템에 대한 접근을 방지합니다. 이 공급자의 인스턴스를 생성하려면 공급자를 대상으로 한 모든 요청에 대해 기본 경로 역할을 하는 (그리고 경로 외부에 대한 접근을 제한하는) 디렉터리 경로를 반드시 제공해야 합니다. ASP.NET Core 응용 프로그램에서는 PhysicalFileProvider 공급자의 인스턴스를 직접 생성하거나, 컨트롤러 또는 서비스의 생성자에서 의존성 주입을 통해서 IFileProvider를 요청할 수 있습니다. 일반적으로 후자의 접근 방식이 보다 유연하고 테스트 가능한 솔루션을 만들어줍니다.

다음 예제는 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

하위 경로를 지정해서 디렉터리의 내용을 반복하거나 특정 파일의 정보를 가져올 수도 있습니다.

컨트롤러에서 공급자를 사용하려면 공급자를 컨트롤러의 생성자 매개 변수로 지정한 다음, 전달받은 공급자 개체를 필드에 할당합니다. 그리고 액션 메서드에서는 이 지역 인스턴스를 사용합니다:

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 클래스에서 공급자를 생성합니다:

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를 반복 조회합니다:

@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>

결과는 다음과 같습니다:

File provider sample application listing physical files and folders

EmbeddedFileProvider

EmbeddedFileProvider는 어셈블리에 포함된 파일에 접근하기 위한 용도로 사용됩니다. .NET Core에서는 .csproj 파일의 <EmbeddedResource> 요소에 지정된 파일들이 어셈블리에 포함됩니다:

<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 패턴을 사용할 수 있습니다. 이 패턴을 사용하면 하나 이상의 파일을 지정할 수 있습니다.

노트

실제로 프로젝트의 모든 .js 파일을 어셈블리에 포함시키고 싶지는 않을 것입니다. 이번 예제는 단지 설명을 위한 것입니다.

EmbeddedFileProvider를 생성할 때, 생성자에게 읽고자 하는 어셈블리를 전달해야 합니다.

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

이 스니핏은 현재 실행중인 어셈블리에 접근하는 EmbeddedFileProvider를 생성하는 방법을 보여줍니다.

앞의 예제 응용 프로그램을 EmbeddedFileProvider를 사용하도록 변경하면 다음과 같은 결과가 출력됩니다:

File provider sample application listing embedded files

노트

어셈블리에 포함된 리소스는 디렉터리를 노출하지 않는 반면, 파일명 자체에 . 구분자를 이용한 리소스의 경로가 (네임스페이스로) 포함되어 있습니다.

EmbeddedFileProvider의 생성자에 선택적 baseNamespace 매개 변수를 전달할 수도 있습니다. 이 매개 변수를 지정하면 전달된 네임스페이스 하위의 리소스를 대상으로만 GetDirectoryContents 호출의 범위가 제한됩니다.

CompositeFileProvider

CompositeFileProviderIFileProvider의 인스턴스들을 결합해서 다수의 공급자를 이용한 파일 작업을 처리할 수 있는 단일 인터페이스를 제공합니다. CompositeFileProvider를 생성할 때는 생성자에 하나 이상의 IFileProvider 인스턴스를 전달합니다:

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

이전 절들에서 구성한 물리적 공급자와 임베디드 공급자를 모두 포함하는 CompositeFileProvider를 사용하도록 예제 응용 프로그램을 수정해보면 다음과 같은 결과가 출력됩니다:

File provider sample application listing both physical files and folders and embedded files

변경 사항 감지하기

IFileProviderWatch 메서드를 이용하면 여러 파일 및 디렉터리의 변경 사항을 감지할 수 있습니다. 이 메서드는 Globbing 패턴을 이용해서 복수의 파일을 지정할 수 있는 경로 문자열을 전달받고 IChangeToken을 반환합니다. 이 토큰은 변경 여부 확인에 사용할 수 있는 HasChanged 속성과, 지정된 경로 문자열에서 변경 내용이 감지되면 호출되는 RegisterChangeCallback 메서드를 제공합니다. 각 변경 토큰은 단일 변경에 대한 응답으로 자신과 연결된 콜백만 호출한다는 점에 주의하시기 바랍니다. 모니터링을 지속적으로 수행하기 위해서는 다음 예제처럼 TaskCompletionSource를 활용하거나 변경 사항에 대한 응답에서 다시 IChangeToken 인스턴스를 생성해야 합니다.

다음 예제는 텍스트 파일이 수정될 때마다 콘솔 응용 프로그램이 메시지를 표시하도록 구성됩니다:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;

namespace WatchConsole
{
    public class Program
    {
        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");
        }
    }
}

파일을 여러 번 저장한 결과는 다음과 같습니다:

Command window after executing dotnet run shows the application monitoring the quotes.txt file for changes and that the file has changed five times.

노트

Docker 컨테이너나 네트워크 공유 같은 일부 파일 시스템은 변경 알림을 안정적으로 전송할 수 없습니다. 그러나 DOTNET_USE_POLLINGFILEWATCHER 환경 변수를 1이나 true로 설정하면 파일 시스템이 4 초마다 폴링됩니다.

Globbing 패턴

파일 시스템 경로는 Globbing 패턴이라고도 부르는 와일드 카드 패턴을 사용합니다. 이 단순 패턴들을 이용해서 파일 그룹을 지정할 수 있습니다. 두 개의 와일드 카드 문자는 *** 입니다.

*

현재 폴더 수준의 모든 항목, 모든 파일명 또는 모든 파일 확장자와 일치합니다. 파일 경로의 /. 문자에 의해서 일치가 중단됩니다.

**

여러 디렉터리 수준의 모든 항목과 일치합니다. 디렉터리 계층 내에서 많은 파일들을 재귀적으로 일치시키기 위해서 사용할 수 있습니다.

Globbing 패턴 예제

directory/file.txt

지정한 디렉터리의 지정한 파일과 일치합니다.

directory/*.txt

지정한 디렉터리에 존재하는 확장자가 .txt인 모든 파일과 일치합니다.

directory/*/bower.json

directory 디렉터리의 한 수준 아래의 모든 하위 디렉터리들의 모든 bower.json 파일과 일치합니다.

directory/**/*.txt

directory 디렉터리의 하위의 모든 위치에 존재하는 확장자가 .txt인 모든 파일과 일치합니다.

ASP.NET Core의 파일 공급자 사용

ASP.NET Core에서는 다양한 부분에서 파일 공급자를 활용합니다. 예를 들어서, IHostingEnvironment는 응용 프로그램의 콘텐츠 루트와 웹 루트를 IFileProvider 형식으로 노출합니다. 정적 파일 미들웨어는 파일 공급자를 이용하여 정적 파일을 찾습니다. Razor는 뷰를 찾기 위해 IFileProvider를 빈번하게 사용합니다. Dotnet의 게시 기능은 파일 공급자와 Globbing 패턴을 사용해서 게시해야 할 파일을 지정합니다.

응용 프로그램에서 사용시 권장 사항

ASP.NET Core 응용 프로그램에 파일 시스템에 접근해야 할 때, 본문의 예제에서 살펴본 것처럼 의존성 주입을 통해서 IFileProvider의 인스턴스를 요청한 다음, 해당 인스턴스의 메서드를 사용해서 접근 작업을 수행할 수 있습니다. 이 방식을 사용하면 응용 프로그램이 시작될 때 한 번만 공급자를 구성해서 응용 프로그램이 생성하는 구현 형식의 인스턴스 개수를 줄일 수 있습니다.

COPYRIGHT © 2001-2017 EGOCUBE. ALL RIGHTS RESERVED.
Total Visit Count: 9,712,730, v1.9.0.28773 β