ASP.NET MVC 6 시작하기

등록일시: 2014-10-27 08:00,  수정일시: 2016-09-02 05:57
조회수: 13,102
이 문서는 ASP.NET vNext 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

ASP.NET의 차기 버전인 가칭 "ASP.NET vNext"는 현대적인 클라우드 기반의 응용 프로그램을 위한 가볍고 조합 가능한 .NET 스택을 만든다는 목표를 갖고 기초부터 철저하게 재설계되었습니다.

본 자습서에서는 MVC, Web API, 그리고 Web Pages가 하나로 통합된, 새로운 ASP.NET MVC 6 프레임워크에 관해서 살펴봅니다.

ASP.NET vNext에서는 MVC 프레임워크, Web API 프레임워크, 그리고 Web Pages 프레임워크가 MVC 6라는 이름의 단일 프레임워크로 모두 통합되었습니다. 이렇게 새로운 프레임워크가 도입됨으로써 기존의 MVC 프레임워크와 Web API 프레임워크 간에 중복된 많은 부분들이 제거되었으며, 라우팅, 액션 선택, 필터, 모델 바인딩 등에 대해 일련의 공통적인 개념들이 사용될 수 있게 되었습니다. 또한 새로운 프레임워크 하나만 사용해서 UI (HTML) 및 Web APIs를 모두 작성할 수 있습니다.

본문은 여러분이 MVC 5나 Web API 2에 익숙하다고 가정하고 있습니다. 만약 그렇지 않다면, ASP.NET MVC에서 사용되는 다음과 같은 전문 용어들을 참고하시기 바랍니다.

  • 컨트롤러(Controller)는 HTTP 요청을 처리하고 응용 프로그램 로직을 실행합니다.
  • 액션(Actions)은 컨트롤러에 정의된 메서드로, HTTP 요청을 처리하기 위해서 호출됩니다. 또한 액션의 반환 값은 HTTP 응답을 구성하기 위해서 사용됩니다.
  • 라우팅(Routing)은 특정 HTTP 요청에 대응해서 호출될 액션을 선택하기 위한 메커니즘으로, 대부분의 경우 URL 경로와 HTTP 동사가 액션 선택의 근거로 활용됩니다.
  • 뷰(View)는 HTML을 렌더하기 위한 구성 요소입니다. 컨트롤러는 뷰를 이용해서 HTTP 응답에 포함될 HTML을 렌더합니다.
  • 모델(Model)은 응용 프로그램의 도메인 데이터를 표현하는 개체입니다. 모델은 대부분 응용 프로그램에 의해서 HTML로 렌더되거나 JSON 같은 데이터 형식으로 직렬화됩니다.
  • Razor 구문은 웹 페이지에 서버 기반의 코드를 삽입하기 위한 간결한 프로그래밍 구문입니다.

다만, 여기에 정리된 용어들 중 몇몇은 ASP.NET에 보다 특화된 관점에서 정의된 것입니다. 가령, ASP.NET MVC에서 컨트롤러는 특정 목적으로 사용되지만, "모델-뷰-컨트롤러(Model-View-Controller)"는 보다 범용적인 패턴으로써 다양한 프레임워크들에서 사용되고 있습니다.

MVC 6 프로젝트는 Visual Studio "14"를 이용해서 생성하거나 빌드할 수 있습니다. 이에 관한 더 자세한 정보는 ASP.NET vNext 및 Visual Studio "14" 시작하기를 참고하시기 바랍니다. 또한 명령 프롬프트를 이용해서 MVC 6 응용 프로그램을 빌드하거나 실행할 수도 있는데, 명령 프롬프트 도구들을 이용하려면, 먼저 프로젝트 위키의 지시를 수행해야 합니다.

가장 간단한 vNext 프로젝트는 다음과 같은 두 가지 파일로 구성됩니다:

  • project.json. 이 파일은 응용 프로그램의 의존성 정보들을 담고 있습니다.
  • 시작 클래스. 이 클래스를 이용해서 응용 프로그램의 HTTP 요청 파이프라인을 구성할 수 있습니다.

만약 Visual Studio "14"를 사용하고 있다면, ASP.NET vNext Empty Web Application 템플릿을 이용해서 이 파일들을 생성해봅니다. 또는, 특정 폴더에서 직접 수작업으로 이 파일들을 생성해도 무방합니다. 가령:

  1. 작업 폴더에 project.json이라는 이름으로 텍스트 파일을 생성한 다음, 다음의 내용을 복사해서 붙여 넣습니다:
    {
        "webroot": "wwwroot",
        "exclude": "wwwroot/**/*.*",
        "dependencies": {
            "Microsoft.AspNet.Diagnostics": "1.0.0-alpha4",
            "Microsoft.AspNet.Hosting": "1.0.0-alpha4",
            "Microsoft.AspNet.Server.WebListener": "1.0.0-alpha4",
            "Microsoft.AspNet.Server.IIS": "1.0.0-alpha4"
        },
        "commands": {
            "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5001"
        },
        "frameworks": {
            "aspnet50": {},
            "aspnetcore50": {}
        }
    }
    노트: Microsoft.AspNet.Server.IIS 패키지는 ASP.NET vNext Empty Web Application 프로젝트를 이용해서 project.json 파일을 생성하고, IIS Express를 이용해서 응용 프로그램을 디버그하고자 하는 경우에만 필요합니다.
  2. 동일한 폴더에 Startup.cs라는 이름으로 또 다른 텍스트 파일을 생성하고, 다음의 내용을 복사해서 붙여 넣습니다:
    using Microsoft.AspNet.Builder;
    
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseWelcomePage();
        }
    }
  3. 마지막으로 wwwroot라는 이름의 하위 폴더를 생성합니다. 이 폴더는 응용 프로그램에 포함될 모든 정적 파일들이 위치하게 될 폴더입니다. 본문에서는 이 폴더를 그냥 빈 상태로 놔두도록 하겠습니다.

기본적으로 vNext의 호스팅 환경은 Startup이라는 이름을 가진 시작 클래스(Startup Class)가 존재할 것이라고 가정합니다. 또한 이 시작 클래스에는 방금 전에 살펴본 것과 같은 시그니처를 갖고 있는 Configure라는 이름의 메서드가 반드시 존재해야만 합니다. 그리고 바로 이 메서드 내부에서 IApplicationBuilder 인터페이스를 이용해서 응용 프로그램을 구성하게 됩니다.

이 코드에서 호출하고 있는 UseWelcomePage 메서드는 간단한 환영 페이지를 출력해주는 기능을 갖고 있는 미들웨어 구성 요소를 추가해줍니다. 이 환영 페이지는 프로젝트가 정상적으로 구성되고 실행되는지를 확인하기 위한 용도로 유용합니다.

노트: 만약 ASP.NET vNext Empty Web Application 템플릿을 이용해서 이 파일들을 생성했다면, 간단히 Start 버튼을 클릭하면 응용 프로그램을 실행할 수 있습니다. 그러나 Visual Studio "14"를 이용해서 파일들을 생성했는지, 또는 텍스트 편집기를 이용해서 수작업으로 직접 생성했는지와 무관하게, 선택에 따라 IIS나 IIS Express 없이 응용 프로그램을 실행할 수 있습니다. 그 구체적인 방법에 관해서는 바로 살펴보도록 하겠습니다.

방금 생성한 간단한 응용 프로그램을 명령 프롬프트에서 경량 웹 리스너를 이용해서 자체-호스트하려면, 먼저 다음과 같은 과정들을 수행해야 합니다:

  1. 명령 프롬프트에서 다음 명령을 실행하여 K 버전 관리자(KVM, K Version Manager)를 설치합니다.
    @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"

    노트: 변경된 정보와 OS X 및 Linux 등 다른 플랫폼들에서 vNext 응용 프로그램을 실행하는 방법에 대해서 알고 싶다면 ASP.NET vNext Home > Getting Started를 참고하시기 바랍니다.

  2. 새로운 환경 변수들을 로드하기 위해서 새로운 명령 프롬프트 세션을 엽니다.
  3. 명령 프롬프트에서 다음의 명령들을 실행합니다: *
    kvm install 1.0.0-alpha4 
    cd <PROJECT.JSON_FOLDER>
    kpm restore
    

여기에서 kvm install 명령은 지정된 버전의 ASP.NET vNext 런타임을 설치합니다. 그리고 kpm restore 명령은 project.json 파일에 설정되어 있는 의존성들을 분석한 다음, 필요한 NuGet 패키지들을 다운로드 받습니다.

노트: kpm 도구는 NuGet 패키지 관리자 설정에 지정된 패키지 피드를 이용해서 패키지들을 복구합니다. ASP.NET vNext 패키지들은 현재 https://www.myget.org/F/aspnetmaster/의 패키지 피드로부터 사용가능 합니다.

이 명령들을 실행하고 나면, 명령 프롬프트에서 응용 프로그램을 자체-호스트할 수 있습니다. 간단히 다음과 같이 입력합니다:

k web

그러면 k web 명령이 HTTP 리스너를 시작합니다. 이 때, 명시적인 빌드 과정이 존재하지 않는다는 점에 주목하시기 바랍니다. k web 명령이 코드를 실시간으로 컴파일하기 때문입니다. 일단 NuGet 패키지들을 설치한 뒤에는, kpm restore 명령을 다시 실행하지 않더라도 코드를 변경하고 k web 명령을 다시 실행할 수 있습니다. **

이제 브라우저를 실행한 다음, http://localhost:5001로 이동합니다. 그러면 다음과 같은 환영 페이지를 확인할 수 있을 것입니다.

web 명령은 다음과 같이 project.json 파일에 정의되어 있습니다:

"commands": {
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5001"
},

이 명령은 호스팅 환경을 시작하고 지정된 로컬호스트 주소에 대한 수신을 대기합니다. 물론, project.json 파일을 수정해서 다른 포트 번호를 사용하도록 변경할 수도 있습니다.

* 만약 kvm install 명령을 수행할 때, 특정 경로에 대한 액세스가 거부되었다는 오류가 발생한다면, 현재 명령 프롬프트를 실행하는 계정이 해당 폴더에 대한 충분한 권한을 갖고 있지 않은 것입니다. 이 경우, 해당 폴더로 이동하여 적절한 ACL 권한을 지정해주시면 됩니다. 그리고 두 번째 명령의 <PROJECT.JSON_FOLDER> 부분에는 project.json 파일이 위치한 폴더의 경로를 입력하면 됩니다. 다시 말해서, 두 번째 명령은 그저 해당 폴더로 이동하는 것이 전부인 셈입니다.

** 직접 테스트를 수행해본 결과, 명령 프롬프트 창을 닫았다가 다시 실행하면 k 명령을 인식하지 못했습니다. 그 이유는 간단한데, k 명령이 존재하는 폴더의 경로가 PATH로 잡혀있지 않기 때문입니다. 이 경로는 kvm install 명령을 실행할 때, 프로세스의 PATH에 등록됩니다. 따라서 명령 프롬프트 창을 닫으면 현재 프로세스가 종료되고, 그 결과 해당 정보가 사라지게 되는 것이죠. 결과적으로 명령 프롬프트를 다시 열게 되면, 새 명령 프롬프트의 프로세스 PATH에는 해당 폴더가 등록되어 있지 않으므로, 바로 k web 명령을 실행해보면 k 명령을 인식하지 못하는 것입니다.

잠시 생각해보면 이는 당연한 구현이라고 말할 수 있을 것 같습니다. 가령, 하나의 서버에 다양한 버전의 ASP.NET vNext 런타임이 설치되어 있는 경우, 모든 버전의 KRE bin 폴더가 시스템 환경 변수의 PATH에 등록된다면 어떤 버전의 k 명령이 실행될지는 아무도 예측이 불가능할 것입니다.

따라서 새로운 명령 프롬프트에서 다시 k web 명령을 실행할 때는, 먼저 kvm 명령이나 kvm use 명령의 -p 옵션과 -g 옵션을 사용해서 사용자나 시스템, 또는 프로세스 환경 변수의 PATH에 KRE bin 폴더를 임시 또는 영구적으로 추가하거나, k 명령을 전체 경로로 지정해주셔야 합니다.

정적 파일 서비스하기

그러나 환영 페이지만으로는 재미가 없으므로, 이번에는 정적 파일들을 서비스할 수 있도록 응용 프로그램을 활성화시켜보겠습니다. 다음의 항목을 project.json 파일의 "dependencies" 섹션에 추가하고, kpm restore 명령을 다시 실행해서 필요한 패키지들을 가져옵니다:

"Microsoft.AspNet.StaticFiles": "1.0.0-alpha4"

그리고 다음과 같이 Startup 클래스를 수정합니다.

using Microsoft.AspNet.Builder;
using Microsoft.AspNet.StaticFiles;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticFiles();
    }
}

이제 정적 파일 미들웨어가 응용 프로그램에 존재하는 이미지, 스크립트 파일, 스타일시트 같은 디스크 상에 존재하는 파일들에 대한 요청을 처리하게 됩니다. 그리고 project.json 파일에 지정된 설정에 따라 정적 파일들은 응용 프로그램의 wwwroot 폴더 하위에 위치해야만 합니다.

MVC 6 시작하기

본문의 남은 절들에서는 MVC 6의 기능들을 몇 가지 살펴보도록 하겠습니다. 먼저 다음의 항목을 project.json 파일의 "dependencies" 섹션에 추가하고 kpm restore 명령을 실행하여 필요한 패키지들을 가져옴으로써 MVC를 활성화시킵니다:

"Microsoft.AspNet.Mvc": "6.0.0-alpha4"

그리고 다음과 같이 Startup 클래스를 수정합니다.

using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseServices(services =>
        {
            services.AddMvc();
        });

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "Default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

이 코드는 MVC를 활성화시키고 라우트를 정의합니다. 만약, 이전 버전의 MVC를 사용해본 경험이 있다면 MapRoute 메서드가 친숙할 것입니다. MVC 5와 MVC 6의 동일한 라우트 정의를 비교해보면 다음과 같습니다:

// MVC 5 route
routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

// MVC 6 route
routes.MapRoute(
    name: "Default",
    template: "{controller=Home}/{action=Index}/{id?}"
);

MVC 6에서는 인라인으로 라우트 템플릿에 기본 라우트 값들을 지정할 수 있다는 점에 주목하시기 바랍니다. 그리고 템플릿에 사용된 '?' 문자는 {id} 세그먼트가 선택적임을 뜻합니다.

이번에는 컨트롤러 클래스를 추가해보겠습니다. 다음 컨트롤러는 뷰를 반환하는 Index라는 이름의 단일 액션 메서드를 정의합니다.

using Microsoft.AspNet.Mvc;

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

이 코드는 네임스페이스만 제외한다면 MVC 5에서도 컴파일 될 것입니다.

그러면 계속해서 뷰를 추가해보겠습니다. .\Views\Home\index.cshtml이라는 파일을 생성하고 다음의 코드를 붙여 넣습니다.

@{
    var message = "Hello World";
}

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Index Page</title>
</head>
<body>
    <h1>@message</h1>
    <p>Index page</p>
</body>
</html>

이 파일은 정적 HTML 파일이 아닌 Razor 파일이라는 점을 명확하게 보여주기 위해서 @message 변수를 정의해서 사용하고 있습니다.

이제 작업 폴더나 Visual Studio 프로젝트의 파일 구조는 다음과 같은 모습일 것입니다:

.\HomeController.cs
.\project.json
.\Startup.cs
.\Views\Home\Index.cshtml
.\wwwroot

다시 k web 명령을 실행해서 응용 프로그램을 실행한 다음, 브라우저에서 http://localhost:5001로 이동해봅니다. 그러면 Index 뷰에 의해서 렌더된 HTML을 다음과 같이 확인할 수 있을 것입니다.

뷰 모델

MVC 6에서도 뷰에 모델을 전달할 수 있습니다. 먼저, 모델 클래스부터 추가해보겠습니다:

public class MessageModel
{
    public string Message { get; set; }
}

그런 다음, MessageModel 클래스의 인스턴스를 View 메서드에 전달하도록 액션을 수정합니다:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MessageModel { Message = "Hello ASP.NET" };
        return View(model);
    }
}

마지막으로 전달 받은 모델을 참조하도록 index.cshtml을 수정합니다.

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Hello World Page</title>
</head>
<body>
    <h1>@Model.Message</h1>
</body>
</html>

이제 응용 프로그램을 실행시켜보면 H1 태그에 "Hello ASP.NET"이 렌더될 것입니다.

Web APIs 및 REST 스타일의 액션 생성하기

만약 라우트 템플릿에 {action} 세그먼트 변수가 포함되어 있지 않으면, 프레임워크는 HTTP 동사를 이용해서 액션 이름을 선택합니다. 이런 형태의 라우팅은 현재 버전의 ASP.NET Web API의 규약-기반 라우팅(Convention-Based Routing)과도 비슷한데, REST 스타일 APIs를 작성할 때 유용합니다.

다음은 {action} 변수가 존재하지 않는 라우트 템플릿의 한 가지 사례입니다.

app.UseMvc(routes =>
{
    routes.MapRoute("ApiRoute", "{controller}/{id?}");
});

이 라우트 템플릿을 사용하면 액션 이름이 요청의 HTTP 동사와 매핑됩니다. 이를테면, GET 요청은 Get이라는 이름의 메서드를 호출하고, PUT 요청은 Put이라는 이름의 메서드를 호출하는 식입니다. 물론, 이 경우에도 {controller} 변수는 계속 컨트롤러 이름과 매핑됩니다.

다음은 이런 형태의 라우팅을 사용하는 컨트롤러입니다.

using Microsoft.AspNet.Mvc;

public class ValuesController : Controller
{
    // GET /values
    public string Get()
    {
        return "Values";
    }
    
    // GET /values/1
    public string Get(int id)
    {
        return "Value " + id.ToString();
    }

    // POST /values
    public ActionResult Post()
    {
        return new HttpStatusCodeResult(201);
    }
}

다음 표는 ValuesController에 정의된 Web API를 보여줍니다.

요청 메서드 URI 경로 컨트롤러 액션
GET /values Get
GET /values/1 Get(id)
POST /values Post

이 컨트롤러 클래스의 처음 두 가지 Get 액션들은 문자열을 반환합니다. 이런 경우, 프레임워크는 반환된 문자열을 HTTP 응답의 본문에 기록하고 Content-Type 헤더를 "text/plain"으로 설정합니다. 가령, /values/1로 GET 요청을 전송하는 경우, 다음과 비슷한 응답이 반환될 것입니다.

HTTP/1.1 200 OK
Content-Type: text/plain
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 30 Apr 2014 00:16:38 GMT
Content-Length: 7

Value 1

반면, 마지막 Post 액션은 HttpStatusCodeResult 개체를 반환합니다. 그러면 프레임워크가 이를 HTTP 상태 코드로 변환해줍니다.

HTTP/1.1 201 Created
Content-Length: 0
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 30 Apr 2014 00:18:58 GMT

만약 ASP.NET Web API에 익숙하다면, 이 ValuesControllerApiController 클래스가 아닌 일반 Controller 클래스로부터 파생되었다는 점을 눈치챘을 지도 모릅니다. 그 이유는 vNext에는 Web APIs를 위한 별도의 컨트롤러 클래스가 존재하지 않기 때문입니다.

기존의 ASP.NET 프레임워크에서는 MVC 5와 Web API 2가 완전히 별도의 클래스들과 네임스페이스들을 사용합니다. 다시 말해서, 특정 컨트롤러는 MVC 컨트롤러거나 Web API 컨트롤러거나 둘 중 하나라는 뜻으로, Web API 컨트롤러의 경우 별도의 라우트를 사용하며 MVC의 필터나 모델 바인더를 사용할 수 없습니다.

기본적인 ASP.NET vNext의 목표들 중 한 가지는 MVC와 Web API를 단일 프레임워크로 통합시켜서 단일 파이프라인을 공유하고 동일한 라우팅, 액션 선택, 필터, 모델 바인딩 등을 사용할 수 있도록 만드는 것입니다. 그 결과, 보다 일관성 있는 프로그래밍 모델과 재사용 할 수 있는 더 많은 코드를 얻을 수 있게 되었습니다.

형식화된 데이터 반환하기

필요한 경우 액션에서 개체를 반환할 수도 있습니다. 이 때, 프레임워크가 요청의 헤더와 사용 가능한 포멧터들에 기반해서 적절한 응답 형식을 선택하도록 할 수 있는데, 이 과정을 콘텐트-협상(Content-Negotiation)이라고 부릅니다. 가령, 다음과 같은 Movie라는 이름의 모델 클래스를 가정해보겠습니다.

public class Movie
{
    public string Title { get; set; }
    public int Year { get; set; }
    public string Genre { get; set; }
}

다음은 이 Movie 클래스의 인스턴스 목록을 JSON 형식으로 반환해주는 컨트롤러입니다. *

using Microsoft.AspNet.Mvc;

public class MoviesController : Controller
{
    public Movie Get()
    {
        var movie = new Movie
        {
            Title = "Maximum Payback", Year = 1990, Genre = "Action"
        };
        return movie;
    }
}

Get 액션의 응답은 다음과 비슷할 것입니다: *

HTTP/1.1 200 OK
Content-Type: application/json
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 25 Sep 2014 04:53:16 GMT
Content-Length: 120

[{"Title":"Maximum Payback","Year":1990,"Genre":"Action"}]

만약 클라이언트가 XML을 요청했다면 응답은 다음과 비슷할 것입니다:

HTTP/1.1 200 OK
Content-Type: application/xml
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 25 Sep 2014 04:53:16 GMT
Content-Length: 195

<Movie xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/test.Models"><Genre>Action</Genre><Title>Maximum Payback</Title><Year>1990</Year></Movie>

또는, 액션에서 Controller.Json 메서드를 호출해서 그냥 JSON을 반환할 수도 있습니다. 이 메서드는 JsonResult 개체를 반환하는데, 이는 개체를 JSON 형식으로 직렬화시키는 액션 결과(Action Result)입니다.

* 이 부분의 설명은 원문의 오류로 보입니다. 액션의 예제 코드는 단건 개체를 반환하도록 작성되어 있는 반면, 설명과 JSON 형식 응답 예제는 마치 배열이 반환되는 것처럼 설명하고 있습니다. 이 점을 참고하시기 바랍니다.

영역

영역(Areas)은 컨트롤러와 모델, 그리고 뷰를 그룹핑하기 위한 방법입니다. 기존 버전의 MVC에서는 AreaRegistration.RegisterAllAreas 메서드를 호출해서 영역을 등록했었습니다. 그리고 영역의 컨트롤러는 해당 영역의 특정 폴더에 위치했었습니다.

MVC 6에서는 {area} 매개변수를 이용해서 라우트 템플릿을 생성한 다음, 영역 컨트롤러에 [Area] 어트리뷰트를 지정하는 방식을 사용합니다. 다음 코드는 영역 라우트를 정의합니다.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "AreasRoute",
        template: "{area}/{controller}/{action}");

    routes.MapRoute(
        name: "Default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

이 라우트 설정 하에서는 다음과 같이 두 개의 Home 컨트롤러를 정의할 수 있습니다:

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        // Home/Index
        public ActionResult Index()
        {
            return View();
        }
    }
}

namespace MyApp.Areas.Controllers
{
    [Area("Books")]
    public class HomeController : Controller
    {
        // Books/Home/Index
        public ActionResult Index()
        {
            return View();
        }
    }
}

여기서 두 번째 Home 컨트롤러는 Books 영역에 할당됩니다.

URI 컨트롤러
/Home/Index MyApp.Controllers.HomeController
/Books/Home/Index MyApp.Areas.Controllers.HomeController

또한 특정 영역에 대응하는 뷰들은 "Areas/{area name}/Views/{controller}"와 같은 형식의 폴더에 위치하게 됩니다. 이를테면, 이번 예제의 경우 Books/Home/Index 액션에 대한 뷰의 경로 및 파일명은 "Areas\Books\Views\Home\index.cshtml"이 됩니다.

기존 Web API 프레임워크에서는 이 영역 기능을 지원하지 않았습니다. 그러나 MVC 6에서는 MVC 프레임워크와 Web API 프레임워크가 하나로 합쳐졌기 때문에, 이제 Web API 스타일의 컨트롤러들을 영역에 위치시킬 수 있게 되었습니다.

뷰 구성 요소 및 자식 뷰

뷰 구성 요소(View Components)는 기존 MVC 버전의 자식 액션(Child Actions)과 비슷합니다. 즉, 뷰에서 특정 액션을 호출하고 그 결과를 뷰에 렌더할 수 있게 해줍니다. 다음 코드는 텍스트 문자열을 기록하는 간단한 뷰 구성 요소를 보여줍니다.

[ViewComponent(Name = "MyViewComponent")]
public class SimpleViewComponent : ViewComponent
{
    public IViewComponentResult Invoke(int num)
    {
        var message = String.Format("The secret code is: {0}", num);
        return Content(message);
    }
}

뷰에서 이 뷰 구성 요소를 포함시키려면 Html.Component 메서드를 호출합니다.

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Index Page</title>
</head>
<body>
    <p>@Component.Invoke("MyViewComponent", 42)</p>
</body>
</html>

뷰가 렌더되면 p 태그에 "The secret code is 42"라는 문자열이 담겨질 것입니다. 뷰 구성 요소를 호출할 때, Invoke 메서드에 매개변수를 전달할 수 있다는 점도 유의해서 살펴보시기 바랍니다.

POCO 컨트롤러

MVC 6에서는 컨트롤러가 반드시 Microsoft.AspNet.Mvc.Controller 클래스로부터 파생되어야 할 필요가 없습니다. 그냥 간단한 클래스나 "POCO(Plain Old CLR Object)"로 컨트롤러를 작성할 수 있습니다. 다음은 그 예입니다.

public class HomeController
{
    // Use the ActivateAttribute to inject services into your controller
    [Activate]
    public ViewDataDictionary ViewData { get; set; }

    public ActionResult Index()
    {
        return new ViewResult() { ViewData = ViewData };
    }
}

여기서 ViewData는 나중에 뷰에서 사용할 수 있는 데이터를 저장할 수 있는 딕셔너리 개체입니다. 이 코드에서 뷰 데이터는 Activate 어트리뷰트가 지정된 ViewData 속성을 통해서 컨트롤러에 주입되고 있다는 점에 유의하시기 바랍니다.

지금까지 본문의 이전 예제들에서는 Controller.View 메서드를 호출해서 뷰를 반환하는 형태의 컨트롤러들을 살펴봤습니다. 그러나 이 메서드는 사실상 Controller 클래스가 제공해주는, ViewResult 개체를 편리하게 반환할 수 있게 해주는 구문상의 도구(Syntactic Sugar)에 불과합니다.

또한 Controller 클래스는 HTTP 요청 컨텍스트, 현재의 보안 주체(IPrincipal), 뷰 백, 그리고 다른 유용한 속성들에 대한 편리한 접근을 제공해줍니다. 따라서 Controller 클래스를 상속 받으면 편리하기는 합니다만, 그렇다고 해서 필수적인 것은 아닙니다. 보다 가벼운 경량의 컨트롤러를 구현하기 위해서는 POCO 컨트롤러가 더 적합한 경우도 있습니다.

피드백 제공하기

피드백을 환영합니다. GitHub의 페이지에서 코멘트로 피드백을 남겨주실 수도 있고, ASP.NET vNext 포럼에 피드백을 남겨주셔도 됩니다. StackOverflow에 질문을 하실 때는 asp.net-vnext 태그를 사용해주십시오. UserVoice 사이트에서 새로운 기능에 대한 제안을 해주셔도 좋습니다.

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