ASP.NET Core의 호스팅 살펴보기

등록일시: 2017-09-18 08:00,  수정일시: 2017-09-15 00:47
조회수: 5,947
이 문서는 ASP.NET Core 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.
본문에서는 ASP.NET Core 응용 프로그램의 구동과 수명을 관리하는 호스트에 관해서 살펴봅니다.

ASP.NET Core 응용 프로그램을 실행하려면, WebHostBuilder 클래스를 이용해서 호스트를 구성하고 구동시켜야 합니다.

호스트란?

ASP.NET Core 응용 프로그램은 응용 프로그램을 실행할 호스트(Host)를 필요로 합니다. 호스트는 다양한 기능 및 서비스들의 모음, 그리고 Start 메서드를 노출하는 IWebHost 인터페이스를 구현합니다. 일반적으로 호스트는 WebHost의 인스턴스를 생성하고 반환하는 WebHostBuilder의 인스턴스를 통해서 만들어집니다. 그리고 이 WebHost는 요청을 처리할 서버를 참조합니다. 이에 대한 보다 자세한 정보는 서버 관련 문서를 참고하십시오.

호스트와 서버의 차이점

호스트는 응용 프로그램의 구동과 수명을 관리하는 반면, 서버는 HTTP 요청을 받아들이는 역할을 수행합니다. 호스트의 역할 중 한 가지는 응용 프로그램의 서비스 및 서버를 사용 가능하도록 적절히 구성하는 것입니다. 단적으로 호스트를 서버를 감싸는 래퍼라고 생각해도 무방합니다. 호스트는 특정 서버를 사용하도록 구성되지만, 서버는 호스트를 인식하지 못합니다.

호스트 설정하기

호스트는 WebHostBuilder의 인스턴스를 이용해서 생성합니다. 대부분 이 작업은 응용 프로그램의 진입점, public static void Main에서 수행됩니다 (프로젝트 템플릿의 경우 Program.cs 파일에 위치해 있습니다). 다음은 일반적인 Program.cs 파일의 코드로, CreateDefaultbuilder 메서드를 호출해서 호스트를 빌드합니다:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

CreateDefaultBuilder 메서드는 응용 프로그램을 서비스 할 서버를 부트스트랩 하는 호스트를 빌드하기 위해서 WebHostBuilder의 인스턴스를 생성합니다. 이를 위해서 호스트에 IServer 인터페이스를 구현한 서버를 제공해야 하는데, 기본 내장 서버로는 KestrelHTTP.sys가 지원되며, CreateDefaultBuilder 메서드는 기본으로 Kestrel을 사용합니다.

웹 서버를 Kestrel로 구성하는 작업 외에도, CreateDefaultBuilder 메서드는 다음과 같은 설정 작업을 수행합니다:

  • 콘텐츠 루트를 Directory.GetCurrentDirectory로 설정합니다.
  • 다음 원본으로부터 구성을 로드합니다:
    • appsettings.json
    • appsettings.<EnvironmentName>.json
    • 응용 프로그램이 개발 환경에서 실행될 경우, 민감한 사용자 정보
    • 환경 변수
    • 전달된 명령줄 인수
  • 로깅 구성 섹션에 지정된 필터링 규칙을 적용해서 콘솔 및 디버그 출력에 대한 로깅을 구성합니다.
  • IIS 통합을 활성화시킵니다.
  • 응용 프로그램이 개발 환경에서 실행될 경우 개발자 예외 페이지를 추가합니다.

서버의 콘텐츠 루트는 서버가 MVC 뷰 파일 같은 콘텐츠 파일을 검색할 위치를 결정합니다. 기본 콘텐츠 루트는 응용 프로그램이 실행되는 폴더입니다.

노트

콘텐츠 루트로 Directory.GetCurrentDirectory를 지정하면, 웹 프로젝트의 루트 폴더에서 응용 프로그램을 실행할 경우, 해당 폴더가 응용 프로그램의 콘텐츠 루트로 사용됩니다 (가령, 웹 프로젝트 폴더에서 dotnet run 명령어를 호출하는 경우). 이 방식이 Visual Studio와 dotnet new 템플릿에서 사용되는 기본 방식입니다.

IIS를 역방향 프록시로 사용할 경우, ASP.NET Core가 호스트를 빌드하는 과정에서 UseIISIntegration 메서드를 자동으로 호출합니다. 더 자세한 정보는 ASP.NET Core 모듈 살펴보기 문서를 참고하시기 바랍니다.

UseIISIntegration 메서드는 UseKestrel 메서드와는 달리 서버를 구성하지 않는다는 점에 주의하십시오. UseKestrel 메서드는 웹 서버를 생성하고 응용 프로그램을 호스트합니다. UseIISIntegration 메서드는 IIS/IIS Express에서 사용되는 환경 변수를 확인하고, 수신 대기할 포트나 사용할 헤더 같은 설정을 구성합니다.

호스트 (그리고 ASP.NET Core 응용 프로그램) 구성의 최소 구현에는 서버와 응용 프로그램의 요청 파이프라인 구성만 포함되면 됩니다:

var host = new WebHostBuilder()
    .UseKestrel()
    .Configure(app =>
    {
        app.Run(async (context) => await context.Response.WriteAsync("Hi!"));
    })
    .Build();

host.Run();
노트

호스트를 설정할 때, Startup 클래스를 지정하는 대신, 혹은 추가로 Configure 메서드나 ConfigureServices 메서드를 지정할 수 있습니다 (이 경우, 해당 메서드들을 정의해야 합니다. 응용 프로그램 Startup 클래스 문서를 참고하시기 바랍니다). ConfigureServices 메서드를 여러 번 호출하면 계속 충첩되고, Configure 메서드나 UseStartup 메서드를 여러 번 호출하면 이전 설정이 대체됩니다.

호스트 구성하기

WebHostBuilder는 사용 가능한 대부분의 호스트 구성 값을 설정할 수 있는 메서드들을 제공하며, 또는 UseSetting 메서드에 관련 키를 지정해서 직접적으로 구성 값을 설정할 수도 있습니다.

호스트 구성 값

Startup 오류 캡처 bool

키: captureStartupErrors. 기본값은 false입니다. 이 키를 false로 설정하면 구동 중 오류가 발생할 경우 호스트가 종료됩니다. 반면 true로 설정하면 호스트가 Startup 클래스에서 발생하는 모든 예외를 캡처하고 서버를 구동하려고 시도합니다. 그리고 모든 요청의 응답으로 오류 페이지가 출력됩니다 (잠시 후 살펴볼 상세 오류 설정에 따라서 일반적인 오류 페이지나 상세 오류 페이지가 출력됩니다). CaptureStartupErrors 메서드를 이용해서 설정할 수 있습니다.

노트: Kestrel 및 IIS에서 응용 프로그램을 실행할 경우의 기본 동작은 구동 시 오류를 캡처하는 것입니다.

new WebHostBuilder()
    .CaptureStartupErrors(true)

콘텐츠 루트 string

키: contentRoot. 응용 프로그램 어셈블리가 위치한 폴더가 기본값입니다 (기본적으로 IIS는 Kestrel에 대해 웹 프로젝트 루트를 사용합니다). 이 설정은 ASP.NET Core가 MVC 뷰 같은 콘텐츠 파일의 검색을 시작할 위치를 결정하며, 웹 루트 설정을 위한 기본 경로로도 이용됩니다. UseContentRoot 메서드를 이용해서 설정할 수 있습니다. 지정된 경로는 반드시 존재해야 하며, 그렇지 않으면 호스트 구동이 실패하게 됩니다.

new WebHostBuilder()
    .UseContentRoot("c:\\mywebsite")

상세 오류 bool

키: detailedErrors. 기본값은 false입니다. 이 키를 true로 설정하면 (또는 환경이 "Development"로 설정되어 있으면) 응용 프로그램이 구동 시 발생한 오류에 대해 일반적인 오류 페이지 대신 상세한 오류 정보를 표시합니다. UseSetting 메서드를 이용해서 설정할 수 있습니다.

new WebHostBuilder()
    .UseSetting("detailedErrors", "true")

상세 오류가 false로 설정되고 Startup 오류 캡처가 true로 설정되면 서버에 대한 모든 요청의 응답으로 일반적인 오류 페이지가 출력됩니다.

Generic error page

그러나 상세 오류가 true로 설정되고 Startup 오류 캡처도 true로 설정되면 서버에 대한 모든 요청의 응답으로 상세한 오류 페이지가 출력됩니다.

Detailed error page

환경 string

키: environment. 기본값은 "Production"입니다. 이 키 값은 어떤 값으로도 설정할 수 있지만, 프레임워크에 정의되어 있는 기본 값으로는 "Development", "Staging" 및 "Production"이 있습니다. 이 값은 대소문자를 구분하지 않습니다. 보다 자세한 정보는 다양한 환경에서 작업하기 문서를 참고하시기 바랍니다. UseEnvironment 메서드를 이용해서 설정할 수 있습니다.

new WebHostBuilder()
    .UseEnvironment("Development")
노트

기본적으로 환경은 ASPNETCORE_ENVIRONMENT 환경 변수로부터 읽혀집니다. Visual Studio를 사용할 경우, launchSettings.json 파일에 환경 변수를 설정할 수 있습니다.

서버 URLs string

키: urls. 세미콜론(;)으로 연결된 서버가 응답해야 하는 URL 접두어의 목록을 설정합니다. 가령, http://localhost:123 같은 값을 말합니다. 서버가 지정된 포트 및 프로토콜을 사용하는 모든 IP 주소 또는 호스트에서 요청을 수신 대기해야 함을 나타내기 위해서 도메인 또는 호스트 이름을 "*"로 대체할 수 있습니다 (예, http://*:5000 또는 https://*:5001). 각 URL에는 프로토콜이 (http:// 또는 https://) 포함되어 있어야 합니다. 접두사는 구성된 서버에 의해 해석되며, 지원되는 형식은 서버마다 다를 수 있습니다.

new WebHostBuilder()
    .UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002")

ASP.NET Core 2.0에서 Kestrel은 자체적인 끝점(Endpoint) 구성 API를 갖고 있으며, urls 문자열에서 https://를 지원하지 않습니다. 보다 자세한 정보는 ASP.NET Core의 Kestrel 웹 서버 구현 살펴보기 문서를 참고하시기 바랍니다.

Startup 어셈블리 string

키: startupAssembly. Startup 클래스를 검색할 어셈블리를 결정합니다. UseStartup 메서드를 이용해서 설정할 수 있습니다. 대신 WebHostBuilder.UseStartup<StartupType>을 사용해서 특정 형식을 참조할 수도 있습니다. UseStartup 메서드가 여러 번 호출되면 마지막 호출이 우선적으로 적용됩니다.

new WebHostBuilder()
    .UseStartup("StartupAssemblyName")

웹 루트 string

키: webroot. 이 키 값을 지정하지 않을 경우, 기본값은 (콘텐츠 루트 경로)\wwwroot입니다 (경로가 존재할 경우). 경로가 존재하지 않으면 아무런 동작도 하지 않는 (no-op) 파일 공급자가 사용됩니다. UseWebRoot 메서드를 이용해서 설정할 수 있습니다.

new WebHostBuilder()
    .UseWebRoot("public")

구성 재정의

구성을 이용해서 호스트가 사용할 구성 값을 설정하십시오. 이 값들은 이후에 재정의 할 수도 있습니다. 구성 값은 UseConfiguration 확장 메서드를 이용해서 지정할 수 있습니다.

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    var host = new WebHostBuilder()
        .UseConfiguration(config)
        .UseKestrel()
        .Configure(app =>
        {
            app.Run(async (context) => await context.Response.WriteAsync("Hi!"));
        })
        .Build();

    host.Run();
}

이 예제에서는 명령줄 인수를 지정해서 호스트를 구성하거나 hosting.json 파일에 선택적으로 구성 설정을 지정할 수 있습니다. 가령, 호스트를 특정 URL에서 실행되도록 지정하려면 명령 프롬프트에서 원하는 값을 전달하면 됩니다:

dotnet run --urls "http://*:5000"

Run 메서드는 웹 응용 프로그램을 시작하고 호스트가 종료될 때까지 호출 스레드를 차단합니다.

host.Run();

또는 Start 메서드를 호출해서 비-차단 방식으로 호스트를 실행할 수도 있습니다.

using (host)
{
    host.Start();
    Console.ReadLine();
}

URL 목록을 Start 메서드에 전달하면 지정된 URL에서 수신을 대기합니다:

var urls = new List<string>()
{
    "http://*:5000",
    "http://localhost:5001"
};

var host = new WebHostBuilder()
    .UseKestrel()
    .UseStartup<Startup>()
    .Start(urls.ToArray());

using (host)
{
    Console.ReadLine();
}

유효한 URL 형식은 사용 중인 서버에 따라서 다릅니다. 보다 자세한 정보는 본문의 서버 URLs 절을 참고하시기 바랍니다.

노트

UseConfiguration 확장 메서드는 GetSection 메서드가 반환한 구성 섹션을 그 상태로 그대로 파싱하지 못합니다 (예, .UseConfiguration(Configuration.GetSection("section")). GetSection 메서드는 지정한 섹션을 대상으로 구성 키를 필터링하지만 키의 섹션 이름을 그대로 놔둡니다 (예, section:urls, section:environment). 그러나 UseConfiguration 확장 메서드는 구성 키가 WebHostBuilder의 키와 일치할 것으로 기대합니다 (예, urls, environment). 따라서 키에 남아 있는 섹션 이름이 섹션 값으로 호스트를 구성하지 못하게 만드는 원인이 됩니다. 이 문제점은 다음 릴리스에서 해결될 예정입니다. 자세한 내용 및 해결 방법은 Passing configuration section into WebHostBuilder.UseConfiguration uses full keys를 참고하시기 바랍니다.

구성 순서 감안하기

WebHostBuilder 설정은 특정 환경 변수가 설정된 경우, 이를 먼저 읽습니다. 이런 환경 변수는 ASPNETCORE_{configurationKey}와 같은 형식을 사용해야 하는데, 가령 서버가 기본적으로 수신 대기하는 URL을 설정하려면 ASPNETCORE_URLS라고 설정하면 됩니다.

이런 모든 환경 변수 값들은 구성을 지정하거나 (UseConfiguration 확장 메서드를 사용해서) 명시적으로 값을 설정해서 (UseUrls 등의 메서드들을 사용해서) 재지정 할 수 있으며, 호스트는 가장 마지막으로 값을 설정한 옵션을 사용합니다. 바로 이런 이유 때문에, UseIISIntegration 메서드를 UseUrls 메서드보다 나중에 호출해야 하는데, IIS가 동적으로 제공하는 URL로 URL을 대체하기 때문입니다. 기본 URL을 프로그래밍적인 방식으로 특정 값으로 설정하지만 구성을 통해서 재정의 할 수 있도록 만들려면, 다음과 같이 호스트를 구성하면 됩니다:

var config = new ConfigurationBuilder()
    .AddCommandLine(args)
    .Build();

var host = new WebHostBuilder()
    .UseUrls("http://*:1000") // default URL
    .UseConfiguration(config) // override from command line
    .UseKestrel()
    .Build();

추가 자료