Katana 프로젝트

등록일시: 2015-07-13 08:00,  수정일시: 2016-09-02 08:57
조회수: 7,134
이 문서는 OWINKatana 프로젝트를 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.
웹 응용 프로그램 개발 방식이 클라우드 컴퓨팅 환경으로 한 단계 더 발돋움함에 따라, ASP.NET 프레임워크도 ASP.NET 응용 프로그램에 기반 구성 요소들을 제공해주고 유연하며 이식이 쉽고 가벼울 뿐만 아니라 더 뛰어난 성능의 ASP.NET 응용 프로그램을 만들 수 있도록 지원해주는 Katana 프로젝트를 통해서 다시 한 번 진화하고 있습니다.

ASP.NET 프레임워크가 처음 등장한 이후 지난 10여 년간, ASP.NET 플랫폼을 기반으로 수 많은 웹 사이트와 서비스들이 개발됐습니다. 그리고 다양한 웹 응용 프로그램 개발 전략들이 점차 발전해나감에 따라 ASP.NET 프레임워크도 ASP.NET MVC나 ASP.NET Web API 같은 기술들을 통해서 역시 함께 발전했습니다. 이제 웹 응용 프로그램 개발 방식이 클라우드 컴퓨팅 환경으로 다시 한 단계 더 발돋움함으로서 ASP.NET 프레임워크도 기반 구성 요소들의 모음을 ASP.NET 응용 프로그램에 제공해주고 보다 유연하며 이식이 쉽고 가벼울 뿐만 아니라 더욱 뛰어난 성능의 ASP.NET 응용 프로그램을 만들 수 있도록 지원해주는 Katana 프로젝트를 통해서 다시 한 번 진화하고 있습니다. 다시 말해서 Katana 프로젝트는 클라우드에 ASP.NET 응용 프로그램을 최적화시켜 줍니다.

왜 Katana인가, 왜 지금인가?

개발자 프레임워크에 관한 논의든 최종 사용자 제품에 관한 논의든, 가장 중요한 점은 어떤 사용자들을 대상으로 만들어진 제품인지를 비롯한 해당 제품을 만들게 된 근본적인 동기를 이해하는 것입니다. 이 점을 감안해 볼 때, ASP.NET은 기본적으로 다음과 같은 두 가지 유형의 고객들을 염두에 두고 만들어졌습니다.

첫 번째 ASP.NET 고객 그룹은 클래식 ASP 개발자들입니다. ASP는 처음 등장하던 당시 마크업과 서버 측 스크립트를 동시에 섞어서 작성하는 방식을 통해서 동적 데이터 기반의 웹 사이트나 응용 프로그램을 만드는 주요 기술들 중 하나였습니다. ASP 런타임은 기반 HTTP 프로토콜과 웹 서버의 핵심 개념들을 추상화시킨 일련의 개체들과 서버 측 스크립트를 동시에 지원했으며, 세션 및 응용 프로그램 상태 관리, 캐시 같은 추가적인 서비스들에 대한 접근을 함께 제공했습니다. 그러나 클래식 ASP 응용 프로그램은 그 강력함에도 불구하고 크기와 복잡도가 증가할수록 관리가 어려워진다는 점이 큰 문제점으로 대두되었습니다. 그 문제점의 대부분은 스크립팅 환경 그 자체와 코드 및 마크업이 서로 뒤섞인 코드 결과물들의 거듭된 복제가 복합적으로 결합되어 발생하는 구조적인 빈약함으로부터 비롯된 결과였습니다. 반면 ASP.NET은 클래식 ASP의 강력함을 계승하면서도 각종 문제점들을 해결하기 위해서 .NET의 개체-지향 언어들이 제공해주는 코드 구조를 활용하는 한편, 클래식 ASP 개발자들에게 익숙한 서버 측 프로그래밍 모델 역시 유지하고 있습니다.

두 번째 ASP.NET 고객 그룹은 Windows 업무용 응용 프로그램 개발자들입니다. WinForms 개발자들은 HTML 마크업 자체와 그 HTML 마크업을 생성하기 위한 코드를 작성하는데 익숙한 클래식 ASP 개발자들과는 달리, 캔버스와 풍부한 사용자 인터페이스 컨트롤들의 모음 같은 디자인 타임 경험에 익숙해져 있었습니다 (기존의 VB6 개발자들처럼). "Web Forms"으로 알려진 ASP.NET의 첫 번째 버전은 Windows 업무용 응용 프로그램 개발과 유사하게 사용자 인터페이스 구성 요소들에 대한 서버 측 이벤트 모델과 일련의 기반구조 기능들을 이용해서 (ViewState 등), 클라이언트 측과 서버 측 프로그래밍 사이에 자연스러운 개발자 경험을 만들어주는 디자인 타임 경험을 제공했습니다. 결과적으로 Web Forms은 WinForms 개발자들에게 친숙한 상태가 존재하는 이벤트 모델의 뒤편으로 상태가 존재하지 않는 웹의 본질을 자연스럽게 감춰줍니다.

기존 모델의 문제점

기존 모델을 이용하면 성숙하고 풍부한 기능의 런타임과 개발자 프로그래밍 모델을 그 결과물로 얻을 수 있었습니다. 그러나 그 풍부한 기능들과 함께 몇 가지 중요한 문제점들도 함께 발생했습니다. 무엇보다 논리적으로 이질적인 단위 기능들이 모두 System.Web.dll 어셈블리 내부에 강력하게 결합된 일체식 구조의 프레임워크라는 점이 가장 큰 문제가 됐습니다 (Web Forms 프레임워크의 핵심 HTTP 개체들 역시 마찬가지 입니다). 두 번째로 ASP.NET이 보다 상위인 .NET 프레임워크의 한 부분으로 포함되어 있는 구조여서 새로운 버전이 배포되기까지 걸리는 시간이 거의 년 단위가 소요된다는 점도 문제가 됐습니다. 결과적으로 이 때문에 ASP.NET은 빠르게 진화해나가는 웹 개발 업계에서 발생하는 다양한 변화에 신속하게 대응하기가 힘들었습니다. 그리고 마지막으로 System.Web.dll 어셈블리 자체가 특정 웹 호스팅 환경, 즉 Internet Information Services(IIS)에 몇 가지 방식으로 강력하게 결합되어 있다는 점도 또 다른 문제였습니다.

점진적인 발전 과정: ASP.NET MVC 그리고 ASP.NET Web API

그 후로도 웹 개발 업계에서는 계속해서 수 많은 변화가 일어났습니다! 웹 응용 프로그램들은 거대한 프레임워크가 아닌 작고 특정 업무에 초점이 맞춰진 일련의 구성 요소들의 모음으로 개발되는 경우가 점점 더 많아지고 있습니다. 비단 구성 요소들의 갯수 뿐만 아니라 구성 요소들이 배포되는 주기도 빠른 속도로 급증하고 있습니다. 웹 개발의 빠른 변화에 적절히 대응하기 위해서는 풍부한 기능의 거대한 프레임워크보다는 상대적으로 작고 분리된 집중적인 프레임워크가 필요하다는 사실이 너무나도 명백하기 때문에, ASP.NET 팀은 몇 단계에 걸쳐서 ASP.NET을 단일 프레임워크가 아닌 조합 가능한 웹 구성 요소들의 모음으로 변화시키기 위해서 점진적인 발전 과정을 밟아왔습니다.

웹 개발의 초기 변화 중 하나는 루비 온 레일즈 같은 웹 개발 프레임워크로 인해서 MVC(Model-View-Controller)로 알려진 디자인 패턴이 급격하게 부상한 것입니다. 이런 형태의 웹 응용 프로그램 구축 방식은 ASP.NET의 초기 장점들 중 하나였던 마크업과 업무 로직의 분리를 유지하면서도 개발자가 응용 프로그램의 마크업을 자유롭게 제어할 수 있게 만들어줍니다. Microsoft는 이런 형태의 웹 응용 프로그램 개발에 대한 요구에 부응하기 위해서 ASP.NET MVC를 제약에서 벗어난 방식으로 자유롭게 개발함으로서 (즉, .NET 프레임워크에 포함시키지 않음으로서) 미래에 보다 나은 위치를 점할 수 있는 기회를 잡았습니다. 또한 ASP.NET MVC는 독립적인 다운로드를 통해서 배포되었으며, 이로 인해서 엔지니어링 팀은 지금까지보다 훨씬 더 자주 업데이트를 배포할 수 있는 유연성을 얻었습니다.

또 다른 웹 응용 프로그램 개발의 중대한 변화는 서버에서 생성되는 동적 웹 페이지를 개발하는 대신, 클라이언트 측 스크립트에서 AJAX 요청을 통해서 백엔드 Web APIs와 통신한 결과로 생성되는 동적 영역이 존재하는 정적인 초기 마크업 페이지를 개발하는 방식으로의 변화 경향을 들수 있습니다. 이와 같은 아키텍처의 변화로 인해서 Web APIs의 부상과 ASP.NET Web API 프레임워크의 개발이 촉진되었습니다. ASP.NET MVC의 경우와 마찬가지로 ASP.NET Web API의 배포 역시 ASP.NET을 보다 모듈 방식의 프레임워크로 발전시킬 수 있는 또 한 번의 기회를 만들어줬습니다. 엔지니어링 팀은 이 기회를 이용해서 ASP.NET Web API를 System.Web.dll 내부에 존재하는 어떤 핵심 프레임워크 형식에도 의존성을 갖지 않도록 만들었습니다. 이로 인해서 두 가지 일이 가능해졌는데, 첫 번째는 ASP.NET Web API가 완벽하게 독립적인 방식으로 발전해나갈 수 있게 됐다는 점입니다 (ASP.NET Web API는 NuGet을 통해서 배포되므로 필요할 때마다 지속적이고 신속하게 배포가 가능합니다). 두 번째는 System.Web.dll에 대한 외부 종속성이 없기 때문에, 자연스럽게 IIS에 대한 종속성도 존재하지 않으므로 ASP.NET Web API를 사용자 지정 호스트(콘솔 응용 프로그램, Windows 서비스 등)에서 실행할 수 있는 능력을 갖게 되었다는 점입니다.

미래: 기민한 프레임워크

이제 프레임워크의 각 구성 요소들이 서로 다른 구성 요소들과 분리되고 NuGet을 통해서 배포됨에 따라, 적절한 시점에 프레임워크를 더 독립적이고 더 빠르게 배포할 수 있게 됐습니다. 그뿐만 아니라 작고 가벼운 호스트를 서비스에 도입하고자 하는 개발자에게 Web API의 자체-호스트 기능이 제공해주는 강력함과 유연함이 대단히 매력적이라는 점도 입증됐습니다. 사실 너무나도 매력적이어서 다른 프레임워크들도 탐낼 정도였지만, 반면 각각의 프레임워크가 자신의 기본 주소로 자체 호스트 프로세스에서 실행되고 독립적으로 관리되어야 할 필요성이 대두함으로 인해서 (시작하고 중지하는 등) 새로운 문제점들도 드러났습니다. 가령 현대적인 웹 응용 프로그램들은 일반적으로 정적 파일 서비스, 동적 페이지 생성, Web API, 그리고 보다 최근에는 실시간/푸시 알림 등을 지원합니다. 그러나 이런 각각의 서비스들 모두가 개별적으로 실행되고 관리될 수 있을 것이라는 기대는 그다지 현실적이지가 않습니다.

결국 이런 상황에서 필요한 것은 개발자가 다양한 구성 요소들과 프레임워크들을 조합해서 응용 프로그램을 만들 수 있게 해주고, 그렇게 만들어진 응용 프로그램을 지원되는 호스트에서 실행할 수 있는 단일 호스팅 추상화였습니다.

OWIN (.NET용 오픈 웹 인터페이스)

.NET 커뮤니티의 일부 구성원들은 Ruby 커뮤니티가 Rack으로부터 거둔 성과에 고무되어, .NET을 위한 웹 서버와 프레임워크 구성 요소들 간의 추상화를 만들기 시작했습니다. OWIN 추상화의 두 가지 설계 목표는 무엇보다 단순해야 하고 가급적 다른 프레임워크 형식들에 대해 극히 일부의 의존성만 갖고 있어야 한다는 것입니다. 이 두 가지 목표는 다음과 같은 일들을 가능하게 해줍니다:

  • 새로운 구성 요소를 더 손쉽게 개발하고 사용할 수 있습니다.
  • 응용 프로그램을 비단 호스트 뿐만 아니라, 궁극적으로 모든 플랫폼과 운영 체제들 간에 더 쉽게 이식할 수 있습니다.

이를 바탕으로 만들어진 추상화의 최종 결과물은 두 가지 핵심 요소로 구성됐는데, 환경 사전(Environment Dictionary)이 바로 그 첫 번째 구성 요소입니다. 이 데이터 구조는 HTTP 요청과 응답을 처리하기 위한 모든 상태를 비롯해서, 관련된 모든 서버 상태를 저장하는 역할을 담당합니다. 이 환경 사전은 다음과 같이 정의되어 있습니다:

IDictionary<string, object>

모든 OWIN을 지원하는 웹 서버는 이 환경 사전을 HTTP 요청 및 응답에 대한 본문 스트림과 헤더 컬렉션 데이터로 채워 넣어야 합니다. 그러면 응용 프로그램이나 프레임워크 구성 요소들이 이 사전에 추가적인 값들을 채워 넣거나 갱신하고 응답 본문 스트림에 기록하게 됩니다.

OWIN의 명세서에서는 환경 사전의 형식을 지정하는 외에도 핵심적인 사전의 키/값 쌍들의 목록을 정의하고 있습니다. 가령 다음 표는 HTTP 요청에 필요한 사전의 키들을 보여줍니다:

키 이름 값 설명
"owin.RequestBody" 요청 본문의 Stream입니다. 만약 요청 본문이 필요 없다면 자리 표시자로 Stream.Null을 지정할 수 있습니다. 더 자세한 내용은 OWIN 명세서의 Request Body 절을 참고하시기 바랍니다.
"owin.RequestHeaders" IDictionary<string, string[]> 형식의 요청 헤더들입니다. 더 자세한 내용은 OWIN 명세서의 Headers 절을 참고하시기 바랍니다.
"owin.RequestMethod" 요청의 HTTP 요청 메서드를 (예, "GET", "POST") 담고 있는 string입니다.
"owin.RequestPath" 요청 경로를 담고 있는 string입니다. 반드시 이 경로는 응용 프로그램 대리자의 "루트"에 대해 상대적이어야만 합니다. 더 자세한 내용은 OWIN 명세서의 Paths 절을 참고하시기 바랍니다.
"owin.RequestPathBase" 요청 경로 중 응용 프로그램 대리자의 "루트"에 해당하는 부분을 담고 있는 string입니다. 더 자세한 내용은 OWIN 명세서의 Paths 절을 참고하시기 바랍니다.
"owin.RequestProtocol" 프로토콜의 이름과 버전을 (예, "HTTP/1.0" 또는 "HTTP/1.1") 담고 있는 string 입니다.
"owin.RequestQueryString" HTTP 요청 URI 중 "?" 문자를 제외한 쿼리 문자열 구성 요소를 (예, "foo=bar&baz=quux") 담고 있는 string입니다. 이 값은 빈 문자열을 담고 있을 수도 있습니다.
"owin.RequestScheme" 요청에 사용된 URI 스킴을 (예, "http", "https") 담고 있는 string 입니다. 더 자세한 내용은 OWIN 명세서의 URI Scheme 절을 참고하시기 바랍니다.

그리고 OWIN의 두 번째 핵심 요소는 응용 프로그램 대리자(Application Delegate)로, OWIN 응용 프로그램의 모든 구성 요소들 간에 핵심 인터페이스 역할을 하는 함수 시그니처입니다. 응용 프로그램 대리자의 정의는 다음과 같습니다:

Func<IDictionary<string, object>, Task>;

즉 응용 프로그램 대리자는 환경 사전을 입력 받고 Task를 반환하는 Func 대리자 형식을 간단하게 구현한 함수입니다. 이런 설계는 개발자들에게 몇 가지 함축적인 의미를 던져줍니다:

  • OWIN 구성 요소를 작성하기 위해 필요한 형식 의존성이 극히 적습니다. 결국 OWIN에 대한 개발자의 접근성이 크게 향상됩니다.
  • 비동기 설계로 인해서 컴퓨팅 자원을 효율적으로 처리 가능한, 특히 I/O 집약적 작업에 더욱 효과적인 추상화가 만들어집니다.
  • 실행의 원자적 단위가 응용 프로그램 대리자이기 때문에, 그리고 환경 사전이 대리자의 매개변수로 전달되기 때문에, OWIN 구성 요소들을 손쉽게 서로 연결해서 복잡한 HTTP 처리 파이프라인을 구성할 수 있습니다.

구현의 관점에서 본다면 OWIN은 명세서에 해당합니다 (http://owin.org/html/owin.html). 그리고 그 목표는 차세대 웹 프레임워크가 되는 것이 아니라, 웹 프레임워크와 웹 서버가 상호 작용하는 방법에 대한 사양을 정의하는 것입니다.

만약 여러분이 관심을 갖고 OWIN이나 Katana에 관해서 알아봤다면, Owin NuGet 패키지와 Owin.dll에 대해서도 이미 알고 있을 것입니다. 이 라이브러리는 OWIN 명세서의 4절에서 설명하고 있는 구동 절차를 공식화하고 성문화한 IAppBuilder라는 단 하나의 인터페이스를 포함하고 있습니다. OWIN 서버를 구축하기 위해서 IAppBuilder 인터페이스가 반드시 필요한 것은 아니지만, 구체적인 기준점을 제공해줄뿐만 아니라 Katana 프로젝트의 구성 요소들에 의해서도 사용되고 있습니다.

Katana 프로젝트

OWIN 명세서와 Owin.dll이 커뮤니티의 소유로 커뮤니티 주도 하에서 오픈 소스로 운영되고 있는 반면, Katana 프로젝트는 오픈 소스이기는 하지만 Microsoft에 의해서 만들어지고 배포되는 일련의 OWIN 구성 요소들을 대표하는 프로젝트입니다. 호스트나 서버 같은 주요 기반 구성 요소들에서부터 인증 구성 요소 등의 기능적 구성 요소들과 SignalR이나 ASP.NET Web API 같이 프레임워크에 결합된 구성 요소들까지 모두 이 프로젝트에 포함되어 있습니다. Katana 프로젝트는 다음과 같은 세 가지 목표를 갖고 있습니다:

  • 이식성 - 필요하다면 언제라도 각각의 구성 요소들을 새로운 구성 요소로 손쉽게 대체할 수 있어야 합니다. 그 대상에는 프레임워크나 서버, 호스트를 비롯한 모든 유형의 구성 요소들이 포함됩니다. 이 목표에는 잠재적으로 Microsoft의 프레임워크를 서드 파티의 서버와 호스트에서 실행할 수도 있고, 서드 파티의 프레임워크를 Microsoft의 서버에서 완벽하게 실행할 수도 있다는 의미가 담겨 있습니다.
  • 모듈형/유연성 - Katana 프로젝트의 구성 요소들은 기본적으로 활성화되어 있는 무수히 많은 기능들이 포함되어 있는 다른 많은 프레임워크들과는 달리 작고 집중적이어야 하며, 응용 프로그램 개발자가 자신의 응용 프로그램에 사용할 구성 요소들을 선택할 수 있도록 제어권을 제공해줘야 합니다.
  • 경량/뛰어난 성능/확장성 - Katana 응용 프로그램은 프레임워크에 대한 전통적인 개념을 응용 프로그램 개발자에 의해서 명시적으로 추가되는 작고 집중적인 구성 요소들로 달리 해석함으로서 더 적은 컴퓨팅 자원을 사용할 수 있게 되었고, 결과적으로 다른 형태의 서버나 프레임워크들 보다 더 많은 작업을 처리할 수 있습니다. 물론 응용 프로그램이 기반 구조로부터 제공되는 기능들을 더 많이 필요로 한다면 이를 OWIN 파이프라인에 추가할 수는 있지만, 그런 경우에는 응용 프로그램 개발자의 명시적인 결정이 있어야만 합니다. 또한 필요한 경우 저수준 구성 요소들을 대체할 수 있기 때문에, 응용 프로그램에 어떠한 문제도 일으키지 않고 새로운 고성능의 서버를 유연하게 도입하여 OWIN 응용 프로그램의 성능을 향상시킬 수 있습니다.

Katana 구성 요소 사용하기

발표되자마자 그 즉시 사람들의 관심을 끌었던 Node.js 프레임워크의 한 가지 특징은, 간단하게 응용 프로그램을 만들어서 웹 서버에서 바로 실행할 수 있다는 점이었습니다. Node.js의 관점에서 Katana의 목표를 살펴본다면, Katana는 개발자들이 ASP.NET 웹 응용 프로그램 개발에 관한 자신의 지식을 모두 포기하지 않아도 Node.js와 같은 (또는 비슷한 프레임워크들과 같은) 많은 장점들을 제공해준다고도 말할 수 있습니다. 이 말이 사실로 성립하려면 Katana 프로젝트를 이용한 작업도 Node.js에서 작업할 때처럼 간단해야 합니다.

"Hello World!" 구현하기

JavaScript와 .NET 개발의 가장 큰 차이점 중 하나는 바로 컴파일러의 존재 유무입니다. 즉 간단한 Katana 서버의 시작점은 Visual Studio 프로젝트입니다. 다만 가장 최소한의 프로젝트 형식, ASP.NET 웹 응용 프로그램(ASP.NET Web Application) 템플릿의 Empty 템플릿을 사용해서 작업을 시작할 수 있습니다.

그런 다음, 프로젝트에 Microsoft.Owin.Host.SystemWeb NuGet 패키지를 설치합니다. 이 패키지는 ASP.NET 요청 파이프라인에서 실행되는 OWIN 서버를 제공해줍니다. 이 패키지는 NuGet 갤러리에서 찾아볼 수 있으며, Visual Studio 패키지 관리자 대화 상자를 이용해서 설치하거나 패키지 관리자 콘솔에 다음의 명령을 입력해서 설치할 수 있습니다:

install-package Microsoft.Owin.Host.SystemWeb

Microsoft.Owin.Host.SystemWeb 패키지를 설치하면 의존성을 갖고 있는 몇 가지 추가적인 패키지들이 함께 설치됩니다. 그 중 한 패키지가 바로 Microsoft.Owin인데, 이 패키지는 OWIN 응용 프로그램을 개발하기 위한 몇 가지 헬퍼 형식들과 메서드들을 제공해주는 라이브러리입니다. 다음의 "Hello World" 서버는 간단한 구현을 위해서 그 중 일부 형식들을 사용하고 있습니다.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Run(context =>
        {
            context.Response.ContentType = "text/plain";
            return context.Response.WriteAsync("Hello World!");
        });
    }
}

바로 지금 Visual Studio에서 F5 키를 누르면 완벽한 디버깅 지원과 함께 이 극적으로 간단한 서버를 실행할 수 있습니다.

호스트 전환하기

방금 구현한 "Hello World" 예제는 기본적으로 IIS 컨텍스트에서 System.Web을 사용하는 ASP.NET 요청 파이프라인에서 실행됩니다. 물론 이것만으로도 OWIN 파이프라인의 유연성 및 조합성의 이점과 IIS의 관리 기능들과 전반적인 성숙함을 동시에 누릴 수 있기 때문에 그 가치가 상당합니다. 그러나 때로는 IIS가 제공해주는 기능들이 필요 없으면서도 더 작고 더 가벼운 호스트가 요구되는 경우도 많습니다. 이런 경우, 예제와 같은 간단한 웹 서버를 IIS와 System.Web 없이 실행하기 위해서 필요한 것은 무엇일까요?

앞에서 알아본 여러 가지 목표들 중 이식성을 살펴보기 위해서, 간단하게 프로젝트의 출력 폴더에 새로운 서버와 호스트 의존성들을 추가한 다음 호스트를 실행해서 웹 서버 호스트를 명령 프롬프트 호스트로 변경해보겠습니다. 이 예제에서는 OwinHost.exe라는 Katana 호스트에 예제 웹 서버를 호스트하고 HttpListener 기반의 Katana 서버를 이용해보려고 합니다. 다른 Katana 구성 요소들과 비슷하게 다음의 명령을 이용해서 NuGet에서 이 구성 요소들을 가져올 수 있습니다:

install-package OwinHost

명령 프롬프트를 열고 프로젝트의 루트 폴더로 이동한 다음, 그냥 OwinHost.exe를 실행합니다 (이 호스트 프로그램은 프로젝트 루트 하위의 관련 NuGet 패키지의 tools 폴더에 설치됩니다). OwinHost.exe는 기본적으로 HttpListener 기반의 서버를 찾도록 구성되어 있으므로 별도의 추가적인 구성은 필요 없습니다. 이제 웹 브라우저에서 http://localhost:5000/로 이동해보면 콘솔에서 실행되는 응용 프로그램이 응답하는 것을 확인하실 수 있습니다.

역주: 호스트 프로그램이 설치되는 경로는 "..\packages\OwinHost.[설치 버전]\tools\OwinHost.exe"와 같이 버전에 영향을 받으므로 참고하시기 바랍니다.

Katana 아키텍처

Katana의 구성 요소 아키텍처는 다음 그림에서 볼 수 있는 것처럼 응용 프로그램을 호스트, 서버, 미들웨어, 응용 프로그램 의 네 가지 논리적 계층으로 구분합니다. 이러한 구성 요소 아키텍처는 가급적 응용 프로그램을 다시 컴파일하지 않고도 각 계층의 구현을 용이하게 교체할 수 있도록 고안된 결과물입니다.

호스트

호스트는 다음과 같은 역할들을 수행합니다:

  • 기반 프로세스를 관리합니다.
  • 요청을 처리하기 위해 선택된 서버와 OWIN 파이프라인의 구성 결과에 따른 작업 흐름을 조정합니다.

현재 Katana 기반의 응용 프로그램이 선택할 수 있는 호스팅 옵션은 세 가지가 존재합니다:

IIS/ASP.NET: 표준 HttpModule 형식과 HttpHandler 형식을 사용하며, OWIN 파이프라인을 IIS에서 ASP.NET 요청 흐름의 일부로 실행할 수 있습니다. ASP.NET 호스팅 기능을 사용하려면 웹 응용 프로그램의 프로젝트에 Microsoft.AspNet.Host.SystemWeb NuGet 패키지를 설치하면 됩니다. 또한 호스트 및 서버의 역할을 모두 IIS가 수행하므로, 이 NuGet 패키지를 사용할 경우 OWIN의 서버와 호스트 계층 간의 구분이 하나로 합쳐지게 되는데, 결과적으로 이는 SystemWeb 호스트를 사용하면 개발자가 서버를 다른 대체 구현으로 대체할 수 없게 된다는 뜻입니다.

사용자 지정 호스트 Host: Katana 구성 요소 모음을 사용하면 개발자가 콘솔 응용 프로그램이나 Windows 서비스 같은 자신만의 사용자 지정 프로세스에서 응용 프로그램을 호스트 할 수 있습니다. 이 기능은 Web API에서 제공되는 자체-호스트(Self-Host) 기능과 매우 비슷합니다. 가령 다음 예제는 Web API의 사용자 지정 호스트 코드를 보여줍니다:

static void Main()
{
    var baseAddress = new Uri("http://localhost:5000");

    var config = new HttpSelfHostConfiguration(baseAddress);
    config.Routes.MapHttpRoute("default", "{controller}");
       
    using (var svr = new HttpSelfHostServer(config))
    {
        svr.OpenAsync().Wait();
        Console.WriteLine("Press Enter to quit.");
        Console.ReadLine();
    }
}

다음과 같은 Katana 응용 프로그램의 자체-호스트 설정도 위와 유사합니다:

static void Main(string[] args)
{
    const string baseUrl = "http://localhost:5000/";

    using (WebApplication.Start<Startup>(new StartOptions { Url = baseUrl }))
    {
        Console.WriteLine("Press Enter to quit.");
        Console.ReadKey();
    }
}

이 코드에서 Web API 자체 호스트 예제와 Katana 자체 호스트 예제 사이에 존재하는 한 가지 중요한 차이점은 Katana 자체 호스트 예제에는 Web API를 구성하는 코드가 존재하지 않는다는 점입니다. Katana는 이식성과 조합성을 모두 만족시키기 위해서 서버를 실행하는 코드와 요청 처리 파이프라인을 구성하는 코드를 따로 분리시켰습니다. 그 결과 Web API를 구성하기 위한 코드는 WebApplication.Start 메서드에 별도로 형식 매개변수로 지정되는 Startup 클래스에 작성됩니다.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        config.Routes.MapHttpRoute("default", "{controller}");
        app.UseWebApi(config);
    }
}

이 Startup 클래스에 대해서는 본문의 뒷부분에서 다시 자세하게 살펴보겠지만, Katana 자체-호스트 프로세스를 시작하는데 필요한 코드는 오늘날 ASP.NET Web API 자체-호스트 응용 프로그램에 사용되는 코드와 상당히 비슷합니다.

OwinHost.exe: 일부 개발자들은 사용자 지정 프로세스를 작성해서 Katana 웹 응용 프로그램을 실행하는 방식을 선호하겠지만, 대부분의 사용자들은 미리 제공된 실행 파일을 실행해서 간단하게 서버를 시작하고 자신의 응용 프로그램을 실행하는 방식을 더 선호합니다. 이런 경우를 위해서 Katana 구성 요소 모음에는 OwinHost.exe가 포함되어 있습니다. 이 실행 파일을 프로젝트의 루트 디렉터리에서 실행하면 자동으로 서버를 시작하고 (기본적으로 HttpListener 서버가 사용됩니다) 규약에 따라 사용자의 Startup 클래스를 찾아서 실행합니다. 또한 몇 가지 추가적인 명령줄 매개변수를 사용해서 이 실행 파일을 보다 세밀하게 제어할 수도 있습니다.

서버

응용 프로그램이 실행될 프로세스를 시작하고 관리하는 것이 호스트의 역할이라면, 서버의 역할은 네트워크 소켓을 열고 요청을 수신한 다음, 이를 사용자에 의해 지정된 OWIN 구성 요소들의 파이프라인에 (눈치챘겠지만 이 파이프라인은 응용 프로그램 개발자의 Startup 클래스에 정의됩니다) 전달하는 것입니다. 현재 Katana 프로젝트에는 두 가지 서버 구현이 포함되어 있습니다:

  • Microsoft.Owin.Host.SystemWeb: 이미 언급했던 것처럼 IIS는 ASP.NET 파이프라인과 함께 호스트 및 서버 모두로 동작합니다. 따라서 이 호스팅 옵션을 선택하게 되면 프로세스 활성화 같은 호스트 수준의 관심사와 HTTP 요청 수신 모두를 IIS가 관리하게 됩니다. 그런 다음 ASP.NET 웹 응용 프로그램의 경우 요청을 ASP.NET 파이프라인으로 전달합니다. 그러면 Katana SystemWeb 호스트가 ASP.NET HttpModule과 HttpHandler를 등록해서 HTTP 파이프라인을 통해서 흐르는 요청을 가로챈 다음, 이를 사용자가 지정한 OWIN 파이프라인을 통해서 전달합니다.
  • Microsoft.Owin.Host.HttpListener: 패키지 이름에서도 알 수 있는 것처럼 Katana 서버는 .NET 프레임워크의 HttpListener 클래스를 이용해서 소켓을 열고 개발자가 지정한 OWIN 파이프라인으로 요청을 전달합니다. 현재 이 구현이 Katana 자체-호스트 API와 OwinHost.exe 양쪽 모두의 기본 서버 선택입니다.

미들웨어/프레임워크

지금까지 살펴본 것처럼 서버는 클라이언트로부터 요청을 받으면 이를 개발자의 구동 코드에 의해서 지정된 OWIN 구성 요소들의 파이프라인을 통해서 전달해야 할 책임을 갖고 있습니다. 바로 이 파이프라인 구성 요소들을 미들웨어라고 합니다.

매우 기초적인 수준에서 볼 때, OWIN 미들웨어 구성 요소는 호출이 가능하도록 OWIN 응용 프로그램 대리자를 구현해야 합니다.

Func<IDictionary<string, object>, Task>

그러나 Katana는 미들웨어 구성 요소를 용이하게 개발하고 조합할 수 있도록, 미들웨어 구성 요소들을 위한 몇 가지 규칙들과 헬퍼 형식들을 제공해줍니다. 그리고 그 중에서 가장 일반적으로 사용되는 것이 OwinMiddleware 클래스입니다. 가령 다음은 이 클래스를 이용해서 구현한 사용자 지정 미들웨어 구성 요소의 한 가지 사례입니다:

public class LoggerMiddleware : OwinMiddleware
{
    private readonly ILog _logger;

    public LoggerMiddleware(OwinMiddleware next, ILog logger) : base(next)
    {
        _logger = logger;
    }

    public override async Task Invoke(IOwinContext context)
    {
        _logger.LogInfo("Middleware begin");
        await this.Next.Invoke(context);
        _logger.LogInfo("Middleware end");
    }
}

이 클래스는 OwinMiddleware 클래스를 상속받고 있으며, 파이프라인의 다음 미들웨어의 인스턴스를 인자로 받은 다음, 이를 다시 기본 생성자에 전달하는 생성자를 구현하고 있습니다. 그리고 이 미들웨어를 구성하기 위해서 필요한 또 다른 인자가 next 매개변수 뒤에 추가적인 생성자 매개변수로 선언되어 있습니다.

이 미들웨어는 런타임 시에 재정의 된 Invoke 메서드를 통해서 실행됩니다. 이 메서드는 OwinContext 형식의 단일 인자를 받습니다. 이 컨텍스트 개체는 앞에서 살펴본 Microsoft.Owin NuGet 패키지에서 제공되며 요청과 응답, 그리고 환경 사전을 비롯한 몇 가지 추가적인 헬퍼 형식들에 대해 강력한 형식의 접근을 제공해줍니다.

이 미들웨어 클래스는 다음과 같이 응용 프로그램의 Startup 클래스 코드를 통해서 손쉽게 OWIN 파이프라인에 추가할 수 있습니다:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use<LoggerMiddleware>(new TraceLogger());
    }
}

Katana 기반구조는 OWIN 미들웨어 구성 요소들을 단순히 하나씩 쌓아서 파이프라인을 구성하기 때문에, 그리고 해당 구성 요소들이 파이프라인에 참여하기 위해서는 단지 응용 프로그램 대리자만 지원하면 되기 때문에, 미들웨어 구성 요소들의 복잡도는 간단한 로거에서부터 ASP.NET, Web API, 또는 SignalR 같은 본격적인 프레임워크에 이르기까지 실로 다양할 수 있습니다. 이를테면 방금 전에 살펴본 OWIN 파이프라인에 ASP.NET Web API를 추가하려면 다음과 같은 구동 코드만 추가하면 됩니다:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use<LoggerMiddleware>(new TraceLogger());
       
        var config = new HttpConfiguration();
        // configure Web API
        app.UseWebApi(config);
       
        // additional middleware registrations
    }
}

또한 Katana 기반구조는 Configuration 메서드에서 IAppBuilder 개체에 추가된 순서대로 미들웨어 구성 요소들의 파이프라인을 구성합니다. 가령 본문의 예제에서 LoggerMiddleware는 요청들이 최종적으로 처리되는 방식과 무관하게 파이프라인을 통해서 흐르는 모든 요청들을 처리할 수 있습니다. 그 결과 특정 미들웨어 구성 요소가 (예, 인증 구성 요소 등) 다양한 구성 요소들과 프레임워크들을 (예, ASP.NET Web API, SignalR, 그리고 정정 파일 서버 등) 포함하고 있는 파이프라인에 대한 요청을 처리하는 강력한 시나리오에 대응할 수 있습니다.

응용 프로그램

방금 예제를 통해서 직접 살펴본 바와 같이, OWIN과 Katana 프로젝트는 새로운 응용 프로그램 프로그래밍 모델이 아닌 응용 프로그래밍 모델 및 프레임워크를 서버와 호스팅 기반구조로부터 분리하기 위한 추상화로 이해해야 합니다. 예를 들어서 Web API 응용 프로그램을 구축할 경우, 응용 프로그램이 Katana 프로젝트의 구성 요소들을 사용해서 OWIN 파이프라인에서 실행되는지 여부와는 전혀 상관 없이 여전히 ASP.NET Web API 프레임워크를 개발자 프레임워크로 사용할 수 있습니다. 또한 응용 프로그램 개발자가 직접 눈으로 확인할 수 있는 OWIN과 관련된 코드는 개발자가 OWIN 파이프라인을 구성하는 위치인 응용 프로그램의 구동 코드, 단 한 곳 뿐입니다. 개발자는 이 구동 코드에 일련의 UseXXX 구문들을 등록하게 되는데, 일반적으로 이 구문들은 전달 받은 요청을 처리할 미들웨어 구성 요소 하나 당 한 구문씩 작성되는 것이 보통입니다. 이와 같은 방식은 현재 System.Web 기반 환경에서 HTTP 모듈을 등록하는 방식과 동일한 결과를 가져오게 됩니다. 대부분 ASP.NET Web API나 SignalR 같은 대규모 프레임워크 미들웨어들은 파이프라인의 끝 부분에 등록됩니다. 반면 인증이나 캐싱 같이 파이프라인 전체에 적용되는(Cross-Cutting) 미들웨어 구성 요소들은 파이프라인의 시작 부분에 등록되어, 그 이후에 등록되는 모든 프레임워크와 구성 요소들에 대한 요청들을 처리하는 것이 일반적입니다. 이처럼 미들웨어 구성 요소들이 다른 미들웨어 구성 요소들이나 기반 구조 구성 요소들과 서로 분리됨으로서, 전반적인 시스템의 안정성은 유지하면서도 각 구성 요소들은 제각기 다른 속도로 발전해나갈 수 있습니다.

구성 요소 - NuGet 패키지

다른 많은 최신 라이브러리나 프레임워크들처럼 Katana 프로젝트의 구성 요소들도 NuGet 패키지로 배포됩니다. 곧 배포될 2.0 버전을 기준으로 볼 때, Katana 패키지의 의존성 그래프는 다음과 같습니다. (그림을 클릭하면 큰 그림을 보실 수 있습니다.)

역주: 2015년 7월 현재 Katana 프로젝트의 최신 버전은 3.0.1입니다.

이 그림에서 볼 수 있는 것처럼 Katana 프로젝트의 거의 모든 패키지들은 직간접적으로 Owin 패키지에 의존성을 갖고 있습니다. 이미 살펴봤듯이 이 Owin 패키지는 OWIN 명세서의 4절에서 설명하고 있는 응용 프로그램 구동 시퀀스의 실제 구현을 제공해주는 IAppBuilder 인터페이스를 포함하고 있습니다. 또한 많은 패키지들이 HTTP 요청 및 응답을 처리하기 위한 헬퍼 형식들을 제공해주는 Microsoft.Owin 패키지에 의존성을 갖고 있습니다. 나머지 패키지들은 각각 호스팅 기반구조 패키지(서버 또는 호스트)나 미들웨어 중 하나로 분류될 수 있습니다. 참고로 이 그림에서 Katana 프로젝트의 외부에 존재하는 패키지 의존성들은 주황색으로 표시되어 있습니다.

참고로 Katana 2.0의 호스팅 기반구조에는 SystemWeb 기반의 서버와 HttpListener 기반의 서버가 모두 포함되어 있는데, OwinHost 패키지는 OwinHost.exe를 사용하는 OWIN 응용 프로그램을 위한 패키지인 반면, Microsoft.Owin.Hosting 패키지는 사용자 지정 호스트(예, 콘솔 응용 프로그램, Windows 서비스 등)에서 자체-호스팅되는 OWIN 응용 프로그램을 위한 것입니다.

기본적으로 Katana 2.0 프로젝트의 미들웨어 구성 요소들은 다양한 인증 방식을 제공해주는데 초점을 맞추고 있습니다. 그리고 진단을 위한 추가적인 미들웨어 구성 요소가 한 가지 제공되는데, 이 패키지는 시작 및 오류 페이지를 지원해줍니다. OWIN이 실질적인 호스팅 추상화로 성장함에 따라, Microsoft와 서드 파티 모두에 의해서 개발되는 미들웨어 구성 요소들의 생태계도 점차 확대될 것으로 보입니다.

결론

이미 설명한 바와 같이 Katana 프로젝트의 목표는 또 다른 웹 프레임워크를 만들어서 개발자들이 이를 강제로 배우게 만들려는 것이 아닙니다. 오히려 .NET 웹 응용 프로그램 개발자들에게 그 어느 때보다 다양한 선택권을 제공해주기 위한 추상화를 만들어내는 것이 그 목표입니다. Katana 프로젝트는 전형적인 웹 응용 프로그램 구조의 논리적 계층들을 교체 가능한 구성 요소들로 분해함으로서 구조 전반에 적용된 구성 요소들을 각각 자신에게 걸맞는 속도로 개선할 수 있게 해줍니다. 또한 Katana 프로젝트는 단순한 OWIN 추상화를 기반으로 모든 구성 요소들을 만들기 때문에, 해당 구성 요소들을 이용해서 구축된 프레임워크와 응용 프로그램들은 다양한 다른 서버나 호스트들 간에도 손쉽게 이식이 가능합니다. 응용 프로그램의 구조를 개발자가 전적으로 제어할 수 있기 때문에, Katana 프로젝트를 이용하면 개발자가 자신의 웹 구조를 얼마나 경량으로 만들지, 아니면 얼마나 풍부한 기능을 도입할지를 완벽하게 선택할 수 있습니다.

Katana에 대한 더 많은 정보

도움을 주신 분들

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