단일 페이지 애플리케이션: KnockoutJS 템플릿

녹아웃 MVC 템플릿은 ASP.NET 및 Web Tools 2012.2의 일부입니다.

ASP.NET 및 Web Tools 2012.2 다운로드

ASP.NET 및 Web Tools 2012.2 업데이트에는 ASP.NET MVC 4용 SPA(Single-Page 애플리케이션) 템플릿이 포함되어 있습니다. 이 템플릿은 대화형 클라이언트 쪽 웹앱 빌드를 빠르게 시작할 수 있도록 설계되었습니다.

"SPA(단일 페이지 애플리케이션)"는 단일 HTML 페이지를 로드한 다음 새 페이지를 로드하는 대신 동적으로 페이지를 업데이트하는 웹 애플리케이션의 일반적인 용어입니다. 초기 페이지 로드 후 SPA는 AJAX 요청을 통해 서버와 협상합니다.

클라이언트 및 서버라는 레이블이 지정된 두 개의 상자를 보여 주는 다이어그램 AJAX라는 레이블이 지정된 화살표가 클라이언트에서 서버로 이동합니다. H TM L로 레이블이 지정된 화살표와 J SON 레이블이 지정된 화살표는 서버에서 클라이언트로 이동합니다.

AJAX는 새로운 것은 아니지만 오늘날에는 정교한 대규모 SPA 애플리케이션을 더 쉽게 빌드하고 유지 관리할 수 있는 JavaScript 프레임워크가 있습니다. 또한 HTML 5 및 CSS3을 사용하면 풍부한 UI를 더 쉽게 만들 수 있습니다.

시작하기 위해 SPA 템플릿은 샘플 "할 일 목록" 애플리케이션을 만듭니다. 이 자습서에서는 템플릿을 단계별 둘러보겠습니다. 먼저 할 일 목록 애플리케이션 자체를 살펴본 다음, 제대로 작동하는 기술 부분을 살펴봅니다.

새 SPA 템플릿 프로젝트 만들기

요구 사항:

  • Visual Studio 2012 또는 웹용 Visual Studio Express 2012
  • ASP.NET Web Tools 2012.2 업데이트. 여기에서 업데이트를 설치할 수 있습니다.

Visual Studio를 시작하고 시작 페이지에서 새 프로젝트를 선택합니다. 또는 파일 메뉴에서 새로 만들기 를 선택한 다음 프로젝트를 선택합니다.

템플릿 창에서 설치된 템플릿을 선택하고 Visual C# 노드를 확장합니다. Visual C#에서 을 선택합니다. 프로젝트 템플릿 목록에서 MVC 4 웹 애플리케이션 ASP.NET 선택합니다. 프로젝트 이름을 지정하고 확인을 클릭합니다.

새 프로젝트 대화 상자를 보여 주는 스크린샷 웹 템플릿 목록에서 SP dot NET M V C 4 웹 애플리케이션이 선택됩니다.

새 프로젝트 마법사에서 단일 페이지 애플리케이션을 선택합니다.

새 ASP 점 NET M V C 4 프로젝트 대화 상자를 보여 주는 스크린샷. 단일 페이지 애플리케이션 템플릿이 선택되어 있습니다.

F5를 눌러 애플리케이션을 빌드 및 실행합니다. 애플리케이션이 처음 실행되면 로그인 화면이 표시됩니다.

내 할 일 목록 로그인 화면을 보여 주는 스크린샷.

"등록" 링크를 클릭하고 새 사용자를 만듭니다.

등록 화면을 보여 주는 스크린샷.

로그인한 후 애플리케이션은 두 개의 항목이 있는 기본 Todo 목록을 만듭니다. "할 일 목록 추가"를 클릭하여 새 목록을 추가할 수 있습니다.

두 개의 할 일 목록과 맨 위에 있는 할 일 목록 추가 단추를 보여 주는 스크린샷.

목록 이름을 바꾸고, 목록에 항목을 추가하고, 검사. 항목을 삭제하거나 전체 목록을 삭제할 수도 있습니다. 변경 내용은 서버의 데이터베이스에 자동으로 유지됩니다(실제로 이 시점에서 로컬로 애플리케이션을 실행하기 때문에 LocalDB).

세 개의 항목이 있는 목록을 보여 주는 스크린샷 마지막 항목이 확인되고 이를 통해 취소됩니다.

SPA 템플릿의 아키텍처

이 다이어그램은 애플리케이션에 대한 기본 구성 요소를 보여줍니다.

클라이언트 및 서버의 별도 구성 요소를 보여 주는 다이어그램 녹아웃 점 js, H T M L 및 J SON은 클라이언트 아래에 있습니다. SP dot NET M V C, S P dot NET Web A P I, Entity Framework 및 Database는 서버 아래에 있습니다.

서버 쪽에서 ASP.NET MVC는 HTML을 제공하고 양식 기반 인증도 처리합니다.

ASP.NET Web API 가져오기, 만들기, 업데이트 및 삭제를 포함하여 ToDoLists 및 ToDoItems와 관련된 모든 요청을 처리합니다. 클라이언트는 JSON 형식의 Web API와 데이터를 교환합니다.

EF(Entity Framework)는 O/RM 계층입니다. 개체 지향 ASP.NET 세계와 기본 데이터베이스 간에 중재합니다. 데이터베이스는 LocalDB를 사용하지만 Web.config 파일에서 변경할 수 있습니다. 일반적으로 로컬 개발에 LocalDB를 사용한 다음, EF 코드 우선 마이그레이션을 사용하여 서버의 SQL 데이터베이스에 배포합니다.

클라이언트 쪽에서 Knockout.js 라이브러리는 AJAX 요청의 페이지 업데이트를 처리합니다. Knockout은 데이터 바인딩을 사용하여 페이지를 최신 데이터와 동기화합니다. 이렇게 하면 JSON 데이터를 안내하고 DOM을 업데이트하는 코드를 작성할 필요가 없습니다. 대신 데이터를 표시하는 방법을 Knockout에 알려주는 선언적 특성을 HTML에 넣습니다.

이 아키텍처의 가장 큰 장점은 프레젠테이션 계층을 애플리케이션 논리와 분리한다는 것입니다. 웹 페이지의 모양에 대해 알 수 없으면 Web API 부분을 만들 수 있습니다. 클라이언트 쪽에서 해당 데이터를 나타내는 "보기 모델"을 만들고 보기 모델은 Knockout을 사용하여 HTML에 바인딩합니다. 이를 통해 보기 모델을 변경하지 않고 HTML을 쉽게 변경할 수 있습니다. (나중에 녹아웃을 살펴보겠습니다.)

모델

Visual Studio 프로젝트에서 Models 폴더에는 서버 쪽에서 사용되는 모델이 포함됩니다. (클라이언트 쪽에는 모델도 있습니다. 이에 대한 자세한 내용은 다음과 같습니다.)

열린 Models 폴더를 보여 주는 스크린샷.

TodoItem, TodoList

다음은 Entity Framework Code First의 데이터베이스 모델입니다. 이러한 모델에는 서로를 가리키는 속성이 있습니다. ToDoList 에는 ToDoItems 컬렉션이 포함되어 있으며 각 ToDoItem 컬렉션에는 부모 ToDoList에 대한 참조가 있습니다. 이러한 속성을 탐색 속성이라고 하며 일대다 관계 할 일 목록과 할 일 항목을 나타냅니다.

또한 클래스는 ToDoItem[ForeignKey] 특성을 사용하여 테이블에 외래 키를 ToDoList 지정 ToDoListId 합니다. 그러면 데이터베이스에 외래 키 제약 조건을 추가하도록 EF에 지시합니다.

[ForeignKey("TodoList")]
public int TodoListId { get; set; }
public virtual TodoList TodoList { get; set; }

TodoItemDto, TodoListDto

이러한 클래스는 클라이언트로 전송될 데이터를 정의합니다. "DTO"는 "데이터 전송 개체"를 의미합니다. DTO는 엔터티를 JSON으로 serialize하는 방법을 정의합니다. 일반적으로 DTO를 사용하는 데는 몇 가지 이유가 있습니다.

  • serialize되는 속성을 제어합니다. DTO는 도메인 모델의 속성 하위 집합을 포함할 수 있습니다. 보안상의 이유로(중요한 데이터를 숨기기 위해) 또는 단순히 보내는 데이터의 양을 줄이기 위해 이 작업을 수행할 수 있습니다.
  • 데이터의 모양을 변경하려면(예: 더 복잡한 데이터 구조를 평면화)
  • DTO에서 비즈니스 논리를 유지하려면(문제 분리)
  • 어떤 이유로 도메인 모델을 serialize할 수 없는 경우. 예를 들어 순환 참조는 개체를 직렬화할 때 문제를 일으킬 수 있습니다. Web API에서 이 문제를 처리하는 방법이 있습니다(순환 개체 참조 처리 참조). 하지만 DTO를 사용하면 문제를 완전히 방지할 수 있습니다.

SPA 템플릿에서 DTO는 도메인 모델과 동일한 데이터를 포함합니다. 그러나 탐색 속성에서 순환 참조를 방지하고 일반적인 DTO 패턴을 보여 주므로 여전히 유용합니다.

AccountModels.cs

이 파일에는 사이트 멤버 자격에 대한 모델이 포함되어 있습니다. 클래스는 UserProfile 멤버 자격 DB의 사용자 프로필에 대한 스키마를 정의합니다. (이 경우 유일한 정보는 사용자 ID 및 사용자 이름입니다.) 이 파일의 다른 모델 클래스는 사용자 등록 및 로그인 양식을 만드는 데 사용됩니다.

Entity Framework

SPA 템플릿은 EF Code First를 사용합니다. Code First 개발에서는 먼저 코드에서 모델을 정의한 다음, EF에서 모델을 사용하여 데이터베이스를 만듭니다. 기존 데이터베이스(Database First)와 함께 EF를 사용할 수도 있습니다.

Models 폴더의 클래스는 TodoItemContextDbContext에서 파생됩니다. 이 클래스는 모델과 EF 간에 "glue"를 제공합니다. 에는 TodoItemContext 컬렉션과 컬렉션이 있습니다 TodoListToDoItem. 데이터베이스를 쿼리하려면 이러한 컬렉션에 대해 LINQ 쿼리를 작성하기만 하면 됩니다. 예를 들어 사용자 "Alice"에 대한 할 일 목록을 모두 선택할 수 있는 방법은 다음과 같습니다.

TodoItemContext db = new TodoItemContext();
IEnumerable<TodoList> lists = 
    from td in db.TodoLists where td.UserId == "Alice" select td;

컬렉션에 새 항목을 추가하거나, 항목을 업데이트하거나, 컬렉션에서 항목을 삭제하고, 변경 내용을 데이터베이스에 유지할 수도 있습니다.

ASP.NET Web API 컨트롤러

ASP.NET Web API 컨트롤러는 HTTP 요청을 처리하는 개체입니다. 언급했듯이 SPA 템플릿은 Web API를 사용하여 및 ToDoItem 인스턴스에서 ToDoList CRUD 작업을 사용하도록 설정합니다. 컨트롤러는 솔루션의 Controllers 폴더에 있습니다.

열려 있는 Controllers 폴더를 보여 주는 스크린샷 Controller dot c s 및 To do List Controller dot c s를 수행하려면 둘 다 빨간색으로 원을 그리게 합니다.

  • TodoController: 할 일 항목에 대한 HTTP 요청을 처리합니다.
  • TodoListController: 할 일 목록에 대한 HTTP 요청을 처리합니다.

Web API가 컨트롤러 이름의 URI 경로와 일치하기 때문에 이러한 이름은 중요합니다. (Web API가 HTTP 요청을 컨트롤러로 라우팅하는 방법을 알아보려면 ASP.NET Web API 라우팅을 참조하세요.)

클래스를 살펴보겠습니다 ToDoListController . 여기에는 단일 데이터 멤버가 포함됩니다.

private TodoItemContext db = new TodoItemContext();

TodoItemContext 앞에서 설명한 대로 EF와 통신하는 데 사용됩니다. 컨트롤러의 메서드는 CRUD 작업을 구현합니다. Web API는 다음과 같이 클라이언트의 HTTP 요청을 컨트롤러 메서드에 매핑합니다.

HTTP 요청 컨트롤러 메서드 설명
GET /api/todo GetTodoLists 할 일 목록의 컬렉션을 가져옵니다.
GET /api/todo/id GetTodoList ID로 할 일 목록을 가져옵니다.
PUT /api/todo/id PutTodoList 할 일 목록을 업데이트.
POST /api/todo PostTodoList 새 할 일 목록을 만듭니다.
DELETE /api/todo/id DeleteTodoList TODO 목록을 삭제합니다.

일부 작업의 URI에는 ID 값에 대한 자리 표시자가 포함되어 있습니다. 예를 들어 ID가 42인 to-list를 삭제하려면 URI는 입니다 /api/todo/42.

CRUD 작업에 Web API를 사용하는 방법에 대한 자세한 내용은 CRUD 작업을 지원하는 웹 API 만들기를 참조하세요. 이 컨트롤러의 코드는 매우 간단합니다. 몇 가지 흥미로운 점은 다음과 같습니다.

  • 메서드는 GetTodoLists LINQ 쿼리를 사용하여 로그인한 사용자의 ID로 결과를 필터링합니다. 이렇게 하면 사용자는 자신이 속한 데이터만 볼 수 있습니다. 또한 Select 문은 인스턴스를 인스턴스로 TodoListDto 변환 ToDoList 하는 데 사용됩니다.
  • PUT 및 POST 메서드는 데이터베이스를 수정하기 전에 모델 상태를 검사. ModelState.IsValid가 false이면 이러한 메서드는 HTTP 400, 잘못된 요청을 반환합니다. 모델 유효성 검사에서 Web API의 모델 유효성 검사에 대해 자세히 알아보세요.
  • 컨트롤러 클래스는 [Authorize] 특성으로 데코레이트됩니다. 이 특성은 HTTP 요청이 인증되었는지 여부를 확인합니다. 요청이 인증되지 않은 경우 클라이언트는 HTTP 401 권한 없음을 받습니다. ASP.NET Web API 인증 및 권한 부여에서 인증에 대해 자세히 알아보세요.

클래스는 TodoController 과 매우 유사합니다 TodoListController. 가장 큰 차이점은 클라이언트가 각 할 일 목록과 함께 할 일 항목을 가져오기 때문에 GET 메서드를 정의하지 않는다는 것입니다.

MVC 컨트롤러 및 뷰

MVC 컨트롤러는 솔루션의 Controllers 폴더에도 있습니다. HomeController는 애플리케이션에 대한 기본 HTML을 렌더링합니다. 홈 컨트롤러에 대한 보기는 Views/Home/Index.cshtml에 정의되어 있습니다. 홈 보기는 사용자가 로그인했는지 여부에 따라 다른 콘텐츠를 렌더링합니다.

@if (@User.Identity.IsAuthenticated)
{
    // ....
}

사용자가 로그인하면 기본 UI가 표시됩니다. 그렇지 않으면 로그인 패널이 표시됩니다. 이 조건부 렌더링은 서버 쪽에서 발생합니다. 클라이언트 쪽에서 중요한 콘텐츠를 숨기려고 시도하지 마세요. HTTP 응답에서 보내는 모든 내용은 원시 HTTP 메시지를 보고 있는 사람에게 표시됩니다.

JavaScript 및 Knockout.js Client-Side

이제 애플리케이션의 서버 쪽에서 클라이언트로 전환해 보겠습니다. SPA 템플릿은 jQuery와 Knockout.js 조합하여 원활하고 대화형 UI를 만듭니다. Knockout.js HTML을 데이터에 쉽게 바인딩할 수 있는 JavaScript 라이브러리입니다. Knockout.js "Model-View-ViewModel"이라는 패턴을 사용합니다.

  • 모델은 도메인 데이터(ToDo 목록 및 ToDo 항목)입니다.
  • 보기는 HTML 문서입니다.
  • 뷰 모델은 모델 데이터를 보유하는 JavaScript 개체입니다. 뷰 모델은 UI의 코드 추상화입니다. HTML 표현에 대한 지식이 없습니다. 대신 "ToDo 항목 목록"과 같은 보기의 추상 기능을 나타냅니다.

뷰는 뷰 모델에 데이터 바인딩됩니다. 뷰 모델에 대한 업데이트 보기에 자동으로 반영됩니다. 바인딩도 다른 방향으로 작동합니다. DOM의 이벤트(예: 클릭)는 AJAX 호출을 트리거하는 뷰 모델의 함수에 데이터 바인딩됩니다.

SPA 템플릿은 클라이언트 쪽 JavaScript를 세 개의 계층으로 구성합니다.

  • todo.datacontext.js: AJAX 요청을 보냅니다.
  • todo.model.js: 모델을 정의합니다.
  • todo.viewmodel.js: 뷰 모델을 정의합니다.

녹아웃 점 j에서 모델 보기로, 모델에서 데이터 컨텍스트로 가는 화살표를 보여 주는 다이어그램 Knockout dot j s와 View Model 사이의 화살표는 데이터 바인딩이라는 레이블이 지정되고 두 항목을 가리킵니다.

이러한 스크립트 파일은 솔루션의 스크립트/앱 폴더에 있습니다.

앱이 열려 있는 레이블이 지정된 하위 폴더를 보여 주는 스크린샷

todo.datacontext 는 Web API 컨트롤러에 대한 모든 AJAX 호출을 처리합니다. (로그인에 대한 AJAX 호출은 ajaxlogin.js 다른 곳에서 정의됩니다.)

todo.model.js 할 일 목록에 대한 클라이언트 쪽(브라우저) 모델을 정의합니다. todoItem 및 todoList의 두 가지 모델 클래스가 있습니다.

모델 클래스의 많은 속성은 "ko.observable" 형식입니다. 관찰 가능 요소는 녹아웃이 마법을 수행하는 방법입니다. Knockout 설명서에서 관찰 가능 항목은 "구독자에게 변경 내용을 알릴 수 있는 JavaScript 개체"입니다. 관찰 가능한 값이 변경되면 Knockout은 관찰 가능한 항목에 바인딩된 모든 HTML 요소를 업데이트합니다. 예를 들어 todoItem에는 타이틀 및 isDone 속성에 대한 관찰 가능 항목이 있습니다.

self.title = ko.observable(data.title);
self.isDone = ko.observable(data.isDone);

코드에서 관찰 가능한 를 구독할 수도 있습니다. 예를 들어 todoItem 클래스는 "isDone" 및 "title" 속성의 변경 내용을 구독합니다.

saveChanges = function () {
    return datacontext.saveChangedTodoItem(self);
};

// Auto-save when these properties change
self.isDone.subscribe(saveChanges);
self.title.subscribe(saveChanges);

모델 보기

뷰 모델은 todo.viewmodel.js 정의됩니다. 뷰 모델은 애플리케이션이 HTML 페이지 요소를 도메인 데이터에 바인딩하는 중심점입니다. SPA 템플릿에서 보기 모델에는 관찰 가능한 todoLists 배열이 포함됩니다. 보기 모델의 다음 코드는 바인딩을 적용하도록 Knockout에 지시합니다.

ko.applyBindings(window.todoApp.todoListViewModel);

HTML 및 데이터 바인딩

페이지의 기본 HTML은 Views/Home/Index.cshtml에 정의되어 있습니다. 데이터 바인딩을 사용하므로 HTML은 실제로 렌더링되는 항목에 대한 템플릿일 뿐입니다. 녹아웃은 선언적 바인딩을 사용합니다. 요소에 "data-bind" 특성을 추가하여 페이지 요소를 데이터에 바인딩합니다. 다음은 Knockout 설명서에서 가져온 매우 간단한 예제입니다.

<p>There are <span data-bind="text: myItems().count"></span> items<p>

이 예제에서 Knockout은 span> 요소의< 내용을 값myItems.count()으로 업데이트합니다. 이 값이 변경되면 문서를 업데이트합니다.

Knockout은 다양한 바인딩 형식을 제공합니다. SPA 템플릿에 사용되는 몇 가지 바인딩은 다음과 같습니다.

  • foreach: 루프를 반복하고 목록의 각 항목에 동일한 태그를 적용할 수 있습니다. 할 일 목록 및 할 일 항목을 렌더링하는 데 사용됩니다. foreach 내에서 바인딩은 목록의 요소에 적용됩니다.
  • 표시 유형: 표시 유형을 토글하는 데 사용됩니다. 컬렉션이 비어 있을 때 태그를 숨기거나 오류 메시지를 표시합니다.
  • value: 양식 값을 채우는 데 사용됩니다.
  • 클릭: 보기 모델의 함수에 클릭 이벤트를 바인딩합니다.

CSRF 방지 보호

CSRF(교차 사이트 요청 위조)는 악의적인 사이트가 사용자가 현재 로그인되어 있는 취약한 사이트에 요청을 보내는 공격입니다. CSRF 공격을 방지하기 위해 ASP.NET MVC는 요청 확인 토큰이라고도 하는 위조 방지 토큰을 사용합니다. 즉, 서버는 임의로 생성된 토큰을 웹 페이지에 배치합니다. 클라이언트가 서버에 데이터를 제출하는 경우 요청 메시지에 이 값을 포함해야 합니다.

위조 방지 토큰은 동일한 원본 정책으로 인해 악의적인 페이지에서 사용자의 토큰을 읽을 수 없으므로 작동합니다. (동일 원본 정책은 서로 다른 두 사이트에서 호스트되는 문서가 서로의 콘텐츠에 액세스하는 것을 방지합니다.)

ASP.NET MVC는 AntiForgery 클래스 및 [ValidateAntiForgeryToken] 특성을 통해 위조 방지 토큰을 기본적으로 지원합니다. 현재 이 기능은 Web API에 기본 제공되지 않습니다. 그러나 SPA 템플릿에는 Web API에 대한 사용자 지정 구현이 포함되어 있습니다. 이 코드는 솔루션의 ValidateHttpAntiForgeryTokenAttribute Filters 폴더에 있는 클래스에 정의됩니다. Web API의 CSRF 방지에 대한 자세한 내용은 CSRF(사이트 간 요청 위조) 공격 방지를 참조하세요.

결론

SPA 템플릿은 최신 대화형 웹 애플리케이션을 빠르게 작성할 수 있도록 설계되었습니다. Knockout.js 라이브러리를 사용하여 데이터 및 애플리케이션 논리와 프레젠테이션(HTML 태그)을 구분합니다. 그러나 녹아웃은 SPA를 만드는 데 사용할 수 있는 유일한 JavaScript 라이브러리가 아닙니다. 다른 옵션을 탐색하려면 커뮤니티에서 만든 SPA 템플릿을 살펴보세요.