OWIN 시작 클래스 감지방식

등록일시: 2015-07-27 08:00,  수정일시: 2016-09-02 08:47
조회수: 6,106
이 문서는 OWINKatana 프로젝트를 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.
본 자습서에서는 단일 OWIN 응용 프로그램에 여러 개의 시작 클래스들을 추가해보고, 그 중 상황에 따라 로드하고자 하는 OWIN 시작 클래스를 선택하고 구성하는 다양한 방법들을 살펴봅니다.

본 자습서에서는 로드할 OWIN 시작 클래스를 구성하는 다양한 방법들을 살펴봅니다. OWIN 자체에 대한 보다 자세한 정보는 Katana 프로젝트 기사를 참고하시기 바랍니다. 본 자습서는 Rick Anderson (@@RickAndMSFT), Praburaj Thiagarajan, 그리고 Howard Dierking (@@howard_dierking)에 의해서 작성되었습니다.

전제조건

Visual Studio 2013

OWIN 시작 클래스 감지방식

모든 OWIN 응용 프로그램은 응용 프로그램의 파이프라인을 구성하는 구성 요소들을 지정할 수 있는 장소인 시작 클래스를 갖고 있습니다. 그리고 여러분이 선택한 호스팅 모델에 따라 (OwinHost, IIS, 또는 IIS 익스프레스 등), 런타임에 시작 클래스를 연결할 수 있는 여러 가지 방법들이 존재합니다. 본 자습서에서 살펴보게 될 시작 클래스 구성 방식들은 모든 호스팅 응용 프로그램에서 사용이 가능합니다. 시작 클래스는 다음 중 한 가지 방법을 이용해서 호스팅 런타임에 연결할 수 있습니다:

  1. 명명 규약: Katana는 어셈블리 이름과 동일한 네임스페이스나 전역 네임스페이스에 존재하는, Startup이라는 이름을 갖고 있는 클래스를 찾습니다.
  2. OwinStartup 어트리뷰트: 가장 많은 개발자들이 시작 클래스를 지정하기 위해서 선택하는 방식입니다. 가령 이 어트리뷰트를 다음과 같이 지정하면 StartupDemo 네임스페이스에 위치한 TestStartup 클래스가 시작 클래스로 설정됩니다.
    [assembly: OwinStartup(typeof(StartupDemo.TestStartup))]
    또한 이 OwinStartup 어트리뷰트는 명명 규약보다 우선 순위가 높습니다. 그리고 이 어트리뷰트를 지정할 때 친숙한 이름을 함께 전달할 수도 있지만, 그러려면 먼저 구성 파일의 appSetting 요소에 미리 친숙한 이름을 설정해놔야 합니다.
  3. 구성 파일의 appSetting 요소: 이 appSetting 요소의 설정이 OwinStartup 어트리뷰트나 명명 규약보다 우선 순위가 더 높습니다. 시작 클래스는 동시에 여러 개가 존재할 수 있으며 (각각 OwinStartup 어트리뷰트가 지정된), 구성 파일에 다음과 비슷한 마크업을 지정해서 실제로 로드될 시작 클래스를 구성할 수 있습니다:
    <appSettings>
      <add key="owin:appStartup" value="StartupDemo.ProductionStartup" />
    </appSettings>
    또는 다음과 같이 사용될 시작 클래스와 어셈블리까지 명시적으로 지정할 수도 있습니다:
    <add key="owin:appStartup" value="StartupDemo.ProductionStartup, StartupDemo" />
    다음 구성 파일의 XML은 ProductionConfiguration이라는 친숙한 시작 클래스 이름을 지정하고 있습니다:
    <appSettings>
      <add key="owin:appStartup" value="ProductionConfiguration" />
    </appSettings>
    그러나 이미 설명했던 것처럼 이 마크업은 다음과 같이 친숙한 이름이 지정된 OwinStartup 어트리뷰트와 함께 사용돼야만 하는데, 그 결과로 ProductionStartup2 클래스가 시작 클래스로 선택되어 실행됩니다:
    [assembly: OwinStartup("ProductionConfiguration", typeof(StartupDemo.ProductionStartup2))]
    
    namespace StartupDemo
    {
        public class ProductionStartup
        {
            public void Configuration(IAppBuilder app)
            {
                app.Run(context =>
                {
                    string t = DateTime.Now.Millisecond.ToString();
                    return context.Response.WriteAsync(t + " Production OWIN App");
                });
            }
        }
    
        public class ProductionStartup2
        {
            public void Configuration(IAppBuilder app)
            {
                app.Run(context =>
                {
                    string t = DateTime.Now.Millisecond.ToString();
                    return context.Response.WriteAsync(t + " 2nd Production OWIN App");
                });
            }
        }
    }
  4. 마지막으로 OWIN 시작 클래스의 탐색을 비활성화시키려면 다음과 같이 web.config 파일의 appSetting 요소에 값이 false로 설정된 owin:AutomaticAppStartup 키를 추가합니다:
    <add key="owin:AutomaticAppStartup" value="false" />

OWIN 시작 클래스를 이용하는 ASP.NET 웹 응용 프로그램 생성하기

  1. 먼저 Empty 템플릿을 이용해서 StartupDemo라는 이름으로 비어 있는 간단한 ASP.NET 웹 응용 프로그램을 만듭니다.
  2. 그런 다음 NuGet 패키지 관리자(NuGet Package Manager)를 이용해서 Microsoft.Owin.Host.SystemWeb 패키지를 설치합니다. 도구(Tools) 메뉴에서 라이브러리 패키지 관리자(Library Package Manager) 또는 NuGet 패키지 관리자를 선택한 다음, 패키지 관리자 콘솔(Package Manager Console)을 선택하고 다음 명령을 입력합니다:
    Install-Package Microsoft.Owin.Host.SystemWeb
  3. 이제 OWIN 시작 클래스를 추가해야 합니다. Visual Studio 2013에서 프로젝트를 마우스 오른쪽 버튼으로 클릭한 다음, 추가(Add)를 선택하고 다시 새 항목(New Item)을 선택합니다.
  4. 그리고 새 항목 추가(Add New Item) 대화 상자가 나타나면 우상단의 검색란에 OWIN 을 입력해서 Owin 시작 클래스(Owin Startup class)를 찾고 파일명을 Startup.cs로 수정한 다음, 추가(Add) 버튼을 클릭합니다.


    이렇게 Owin 시작 클래스를 한 번 추가하고 나면, 나중에 다시 이 클래스를 추가하고자 할 때, 편리하게 추가(Add) 메뉴 하위에서 바로 선택할 수 있습니다.


    또는 방금 전처럼 프로젝트를 마우스 오른쪽 버튼으로 클릭한 다음, 추가(Add)를 선택하고 다시 새 항목(New Item)을 선택한 다음, 새 항목 추가(Add New Item) 대화 상자에서 Owin 시작 클래스(Owin Startup class)를 선택해도 됩니다.
  5. 자동으로 생성된 Startup.cs 파일의 코드를 다음 코드로 대체합니다:
    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    using System.IO;
    
    //[assembly: OwinStartup(typeof(StartupDemo.Startup))]
    
    namespace StartupDemo
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                app.Use((context, next) =>
                {
                    TextWriter output = context.Get<TextWriter>("host.TraceOutput");
                    return next().ContinueWith(result =>
                    {
                        output.WriteLine("Scheme {0} : Method {1} : Path {2} : MS {3}",
                        context.Request.Scheme, context.Request.Method, context.Request.Path, getTime());
                    });
                });
               
                app.Run(async context =>
                {
                    await context.Response.WriteAsync(getTime() + " My First OWIN App");
                });
            }
          
            string getTime()
            {
                return DateTime.Now.Millisecond.ToString();
            }
        }
    }
    이 코드에 사용된 app.Use 람다 식은 지정한 미들웨어 구성 요소를 OWIN 파이프라인에 등록하기 위해 사용됩니다. 가령 이번 예제에서는 전달 받은 요청에 응답하기 전에 먼저 해당 요청에 대한 로그를 기록하는 미들웨어를 설정하고 있습니다. 참고로 이 람다 식에 전달되는 next 매개변수는 파이프라인 상의 다음 구성 요소에 대한 대리자(Func<Task>)입니다. 그리고 app.Run 람다 식은 들어오는 요청과 파이프라인을 연결하고 응답 메커니즘을 제공해줍니다.
    노트: 이 코드에서는 의도적으로 OwinStartup 어트리뷰트를 주석으로 처리함으로서 Startup이라는 이름의 클래스를 찾는 명명 규약을 적용하고 있다는 점에 유의하시기 바랍니다.
  6. 이제 F5 키를 눌러서 응용 프로그램을 실행하고, 몇 차례 새로 고침을 해봅니다.
    노트: 본 자습서의 그림들에서 볼 수 있는 번호와 여러분이 직접 예제를 실행했을 때 보게 되는 번호들은 거의 대부분 일치하지 않을 것입니다. 이 밀리세컨트 문자열은 단지 페이지를 새로 고칠 때마다 새로운 응답이 생성된다는 것을 증명하기 위한 용도일 뿐입니다. 그리고 출력(Output) 창을 살펴보면 다음과 같이 예제 코드에서 기록하는 추적 정보를 확인할 수 있습니다.

더 많은 시작 클래스 추가하기

이번 절에서는 프로젝트에 또 다른 시작 클래스들을 추가해봅니다. 응용 프로그램에는 여러 개의 OWIN 시작 클래스들이 존재할 수 있는데, 가령 개발용, 테스트용, 그리고 운영용 시작 클래스를 각각 별도로 생성해야 할 경우도 있을 수 있기 때문입니다.

  1. 새로운 OWIN 시작 클래스를 추가하고 그 이름을 ProductionStartup이라고 지정합니다.
  2. 그리고 생성된 코드를 다음 코드로 대체합니다:
    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    
    [assembly: OwinStartup(typeof(StartupDemo.ProductionStartup))]
    
    namespace StartupDemo
    {
        public class ProductionStartup
        {
            public void Configuration(IAppBuilder app)
            {
                app.Run(context =>
                {
                    string t = DateTime.Now.Millisecond.ToString();
                    return context.Response.WriteAsync(t + " Production OWIN App");
                });
            }
        }
    }
  3. F5 키를 눌러서 응용 프로그램을 실행합니다. 그러면 이번에는 OwinStartup 어트리뷰트에 지정된 Production 시작 클래스가 실행된 것을 확인할 수 있습니다
  4. 다시 한 번 새로운 OWIN 시작 클래스를 추가하고 이번에는 이름을 TestStartup으로 지정합니다.
  5. 그리고 이번에도 생성된 코드를 다음 코드로 대체합니다:
    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    
    [assembly: OwinStartup("TestingConfiguration", typeof(StartupDemo.TestStartup))]
    
    namespace StartupDemo
    {
        public class TestStartup
        {
            public void Configuration(IAppBuilder app)
            {
                app.Run(context =>
                {
                    string t = DateTime.Now.Millisecond.ToString();
                    return context.Response.WriteAsync(t + " Test OWIN App");
                });
            }
        }
    }
    이 클래스에서는 OwinStartup 어트리뷰트의 오버로드 버전을 이용해서 시작 클래스의 친숙한 이름으로 TestingConfiguration이라는 이름을 지정하고 있습니다.
  6. Web.config 파일을 열고 시작 클래스의 친숙한 이름을 지정하는 OWIN 응용 프로그램 시작 키를 추가합니다:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <appSettings>
        <add key="owin:appStartup" value="TestingConfiguration" />
      </appSettings>
      <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
      </system.web>
    </configuration>
  7. 다시 응용 프로그램을 실행해보면, Web.config 파일에 지정된 응용 프로그램 설정이 우선순위가 더 높기 때문에 이번에는 Test 구성이 실행됩니다.
  8. 이번에는 TestStartup 클래스의 OwinStartup 어트리뷰트에서 친숙한 이름을 제거합니다.
    [assembly: OwinStartup(typeof(StartupDemo.TestStartup))]
  9. 그리고 Web.config 파일의 OWIN 응용 프로그램 시작 키를 다음과 같이 변경합니다:
    <add key="owin:appStartup" value="StartupDemo.TestStartup" />
  10. 모든 시작 클래스들의 OwinStartup 어트리뷰트를 Visual Studio가 생성해준 기본 코드로 복원합니다:
    [assembly: OwinStartup(typeof(StartupDemo.Startup))]
    [assembly: OwinStartup(typeof(StartupDemo.ProductionStartup))]
    [assembly: OwinStartup(typeof(StartupDemo.TestStartup))]
    참고로 다음 목록의 OWIN 응용 프로그램 시작 키들은 모두 ProductionStartup 클래스를 실행하도록 지정합니다.
    <add key="owin:appStartup" value="StartupDemo.ProductionStartup" />
    <add key="owin:appStartup" value="StartupDemo.ProductionStartup, StartupDemo" />
    <add key="owin:appStartup" value="StartupDemo.ProductionStartup.Configuration, StartupDemo" />
    이 목록의 마지막 시작 키를 살펴보면 시작 클래스의 구성 메서드까지 지정하고 있는 것을 볼 수 있는데, 같은 요령으로 다음과 같이 OWIN 응용 프로그램 시작 키를 지정하면 구성 메서드의 이름을 MyConfiguration으로 변경할 수도 있습니다.
    <add key="owin:appStartup" value="StartupDemo.ProductionStartup2.MyConfiguration" />

Owinhost.exe 사용하기

  1. Web.config 파일을 다음과 같이 변경합니다:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <appSettings>
        <add key="owin:appStartup" value="StartupDemo.Startup" />
        <add key="owin:appStartup" value="StartupDemo.TestStartup" />
      </appSettings>
      <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
      </system.web>
    </configuration>
    지금과 같은 상황에서는 마지막으로 지정한 키가 우선순위가 가장 높기 때문에 TestStartup 클래스가 실행될 것입니다.
  2. 패키지 관리자 콘솔(Package Manager Console)에 다음 명령을 입력해서 Owinhost를 설치합니다:

    Install-Package OwinHost

  3. 명령 프롬프트 창에서 응용 프로그램 폴더로 이동한 다음 (Web.config 파일이 존재하는 폴더), 다음 명령을 입력합니다:

    ..\packages\Owinhost.<Version>\tools\Owinhost.exe

    그러면 명령 프롬프트 창에 다음과 같이 출력될 것입니다.
    C:\StartupDemo\StartupDemo>..\packages\Owinhost.3.0.1\tools\Owinhost.exe
    Starting with the default port: 5000 (http://localhost:5000/)
    Started successfully
    PressEnter to exit
  4. 브라우저를 실행하고 http://localhost:5000/ URL로 이동해봅니다.

    그러면 OwinHost 역시 본문의 첫 부분에서 살펴본 OWIN 시작 클래스를 선택하기 위한 규약을 따른다는 것을 알 수 있습니다.
  5. 명령 프롬프트 창에서 엔터 키를 눌러서 OwinHost를 종료합니다.
  6. 그리고 ProductionStartup 클래스에서 OwinStartup 어트리뷰트에 다음과 같이 ProductionConfiguration 이라는 친숙한 이름을 지정합니다.
    [assembly: OwinStartup("ProductionConfiguration", typeof(StartupDemo.ProductionStartup))]
  7. 그런 다음 다시 명령 프롬프트 창에 다음과 같은 명령을 입력합니다:

    ..\packages\OwinHost.3.0.1\tools\OwinHost.exe ProductionConfiguration

    그러면 이번에는 Production 시작 클래스가 실행되는 것을 확인할 수 있습니다.

    지금까지 본문에서 살펴본 내용들을 정리해보면, OWIN 응용 프로그램은 여러 개의 시작 클래스를 갖고 있을 수 있으며, 그 중 어떤 시작 클래스를 로드할지는 런타임까지 결정을 미뤄둘 수 있음을 알 수 있습니다.
  8. 마지막으로 다음의 런타임 시작 옵션들도 테스트 해보시기 바랍니다:
    ..\packages\OwinHost.3.0.1\tools\OwinHost.exe StartupDemo.TestStartup
    ..\packages\OwinHost.3.0.1\tools\OwinHost.exe "StartupDemo.TestStartup,StartupDemo"
    ..\packages\OwinHost.3.0.1\tools\OwinHost.exe StartupDemo.TestStartup.Configuration
    ..\packages\OwinHost.3.0.1\tools\OwinHost.exe "StartupDemo.TestStartup.Configuration,StartupDemo"

이 기사는 2013년 10월 17일에 최초 작성되었습니다.