다음을 통해 공유


실습: ASP.NET Web API 및 Angular.js를 사용하여 SPA(단일 페이지 애플리케이션) 빌드

웹 캠프 팀

웹 캠프 교육 키트 다운로드

이 실습 랩에서는 ASP.NET 4.x용 ASP.NET Web API 및 Angular.js 사용하여 SPA(단일 페이지 애플리케이션)를 빌드하는 방법을 보여 줍니다.

이 실습 랩에서는 이러한 기술을 활용하여 SPA 개념을 기반으로 하는 퀴즈 웹 사이트인 Geek Quiz를 구현합니다. 먼저 ASP.NET Web API 서비스 계층을 구현하여 퀴즈 질문을 검색하고 답변을 저장하는 데 필요한 엔드포인트를 노출합니다. 그런 다음 AngularJS 및 CSS3 변환 효과를 사용하여 풍부하고 반응성이 뛰어난 UI를 빌드합니다.

기존 웹 애플리케이션에서 클라이언트(브라우저)는 페이지를 요청하여 서버와의 통신을 시작합니다. 그런 다음 서버는 요청을 처리하고 페이지의 HTML을 클라이언트에 보냅니다. 페이지와의 후속 상호 작용(예: 사용자가 링크로 이동하거나 데이터를 사용하여 양식을 제출합니다.) 새 요청이 서버로 전송되고 흐름이 다시 시작됩니다. 서버는 요청을 처리하고 클라이언트가 요청한 새 작업에 대한 응답으로 브라우저에 새 페이지를 보냅니다.

Single-Page SPA(애플리케이션)에서 전체 페이지는 초기 요청 후 브라우저에 로드되지만 후속 상호 작용은 Ajax 요청을 통해 수행됩니다. 즉, 브라우저가 변경된 페이지의 부분만 업데이트해야 합니다. 전체 페이지를 다시 로드할 필요가 없습니다. SPA 접근 방식은 애플리케이션이 사용자 작업에 응답하는 데 걸리는 시간을 줄여 보다 유동적인 환경을 제공합니다.

SPA의 아키텍처에는 기존 웹 애플리케이션에 없는 특정 과제가 포함됩니다. 그러나 ASP.NET Web API, AngularJS와 같은 JavaScript 프레임워크 및 CSS3에서 제공하는 새로운 스타일 지정 기능과 같은 새로운 기술을 사용하면 SPA를 디자인하고 빌드하기가 매우 쉽습니다.

모든 샘플 코드 및 코드 조각은 에서 사용할 수 있는 웹 캠프 교육 키트에 https://aka.ms/webcamps-training-kit포함되어 있습니다.

개요

목표

이 실습 랩에서는 다음 방법을 알아봅니다.

  • JSON 데이터를 보내고 받는 ASP.NET Web API 서비스 만들기
  • AngularJS를 사용하여 반응형 UI 만들기
  • CSS3 변환을 사용하여 UI 환경 개선

사전 요구 사항

이 실습 랩을 완료하려면 다음이 필요합니다.

설치 프로그램

이 실습 랩에서 연습을 실행하려면 먼저 환경을 설정해야 합니다.

  1. Windows Explorer 열고 랩의 원본 폴더로 이동합니다.
  2. Setup.cmd를 마우스 오른쪽 단추로 클릭하고 관리자 권한으로 실행을 선택하여 환경을 구성하고 이 랩에 대한 Visual Studio 코드 조각을 설치하는 설치 프로세스를 시작합니다.
  3. 사용자 계정 컨트롤 대화 상자가 표시되면 계속할 작업을 확인합니다.

참고

설치 프로그램을 실행하기 전에 이 랩에 대한 모든 종속성을 확인했는지 확인합니다.

코드 조각 사용

랩 문서 전체에서 코드 블록을 삽입하라는 지시가 표시됩니다. 편의를 위해 이 코드의 대부분은 수동으로 추가할 필요가 없도록 Visual Studio 2013 내에서 액세스할 수 있는 Visual Studio Code 코드 조각으로 제공됩니다.

참고

각 연습에는 각 연습을 다른 연습과 독립적으로 따를 수 있는 연습의 Begin 폴더에 있는 시작 솔루션이 함께 제공됩니다. 연습 중에 추가된 코드 조각은 이러한 시작 솔루션에서 누락되었으며 연습을 완료할 때까지 작동하지 않을 수 있습니다. 연습의 소스 코드 내에서 해당 연습의 단계를 완료한 결과 코드가 포함된 Visual Studio 솔루션이 포함된 End 폴더도 찾을 수 있습니다. 이 실습 랩을 통해 작업할 때 추가 도움이 필요한 경우 이러한 솔루션을 지침으로 사용할 수 있습니다.


연습

이 실습 랩에는 다음 연습이 포함되어 있습니다.

  1. Web API 만들기
  2. SPA 인터페이스 만들기

이 랩을 완료하는 예상 시간: 60분

참고

Visual Studio를 처음 시작할 때 미리 정의된 설정 컬렉션 중 하나를 선택해야 합니다. 미리 정의된 각 컬렉션은 특정 개발 스타일과 일치하도록 설계되었으며 창 레이아웃, 편집기 동작, IntelliSense 코드 조각 및 대화 상자 옵션을 결정합니다. 이 랩의 절차에서는 일반 개발 설정 컬렉션을 사용할 때 Visual Studio에서 지정된 작업을 수행하는 데 필요한 작업을 설명합니다. 개발 환경에 대해 다른 설정 컬렉션을 선택하는 경우 고려해야 할 단계에 차이가 있을 수 있습니다.

연습 1: Web API 만들기

SPA의 주요 부분 중 하나는 서비스 계층입니다. UI에서 보낸 Ajax 호출을 처리하고 해당 호출에 대한 응답으로 데이터를 반환합니다. 검색된 데이터는 클라이언트에서 구문 분석하고 사용하려면 컴퓨터에서 읽을 수 있는 형식으로 표시되어야 합니다.

Web API 프레임워크는 ASP.NET Stack의 일부이며 일반적으로 RESTful API를 통해 JSON 또는 XML 형식 데이터를 보내고 받는 HTTP 서비스를 쉽게 구현할 수 있도록 설계되었습니다. 이 연습에서는 Geek 퀴즈 애플리케이션을 호스트하는 웹 사이트를 만든 다음, 백 엔드 서비스를 구현하여 ASP.NET Web API 사용하여 퀴즈 데이터를 노출하고 유지합니다.

작업 1 – Geek 퀴즈에 대한 초기 프로젝트 만들기

이 작업에서는 Visual Studio와 함께 제공되는 One ASP.NET 프로젝트 형식을 기반으로 ASP.NET Web API 지원하는 새 ASP.NET MVC 프로젝트를 만들기 시작합니다. 하나의 ASP.NET 모든 ASP.NET 기술을 통합하고 원하는 대로 혼합하고 일치시킬 수 있는 옵션을 제공합니다. 그런 다음 Entity Framework의 모델 클래스와 데이터베이스 이니셜라이저를 추가하여 퀴즈 질문을 삽입합니다.

  1. 웹용 Visual Studio Express 2013을 열고 파일 | 을 선택합니다. 새 프로젝트... 새 솔루션을 시작합니다.

    새 프로젝트 만들기

    새 프로젝트 만들기

  2. 새 프로젝트 대화 상자의 Visual C# | 아래에서 ASP.NET 웹 애플리케이션을 선택합니다. 탭. .NET Framework 4.5가 선택되어 있는지 확인하고, 이름을 GeekQuiz로 지정하고, 위치를 선택하고, 확인을 클릭합니다.

    새 ASP.NET 웹 애플리케이션 프로젝트

    새 ASP.NET 웹 애플리케이션 프로젝트 만들기

  3. 새 ASP.NET 프로젝트 대화 상자에서 MVC 템플릿을 선택하고 Web API 옵션을 선택합니다. 또한 인증 옵션이 개별 사용자 계정으로 설정되어 있는지 확인합니다. 계속하려면 확인 을 클릭합니다.

    Web API 구성 요소를 포함하여 MVC 템플릿을 사용하여 새 프로젝트 만들기

    Web API 구성 요소를 포함하여 MVC 템플릿을 사용하여 새 프로젝트 만들기

  4. 솔루션 탐색기GeekQuiz 프로젝트의 Models 폴더를 마우스 오른쪽 단추로 클릭하고 추가 | 를 선택합니다. 기존 항목....

    기존 항목 추가

    기존 항목 추가

  5. 기존 항목 추가 대화 상자에서 원본/자산/모델 폴더로 이동하여 모든 파일을 선택합니다. 추가를 클릭합니다.

    모델 자산 추가 모델

    모델 자산 추가

    참고

    이러한 파일을 추가하면 데이터 모델, Entity Framework의 데이터베이스 컨텍스트 및 Geek Quiz 애플리케이션에 대한 데이터베이스 이니셜라이저를 추가합니다.

    EF(Entity Framework) 는 관계형 스토리지 스키마를 사용하여 직접 프로그래밍하는 대신 개념적 애플리케이션 모델로 프로그래밍하여 데이터 액세스 애플리케이션을 만들 수 있는 ORM(개체 관계형 매퍼)입니다. Entity Framework에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

    다음은 방금 추가한 클래스에 대한 설명입니다.

    • TriviaOption: 퀴즈 질문과 연결된 단일 옵션을 나타냅니다.
    • TriviaQuestion: 퀴즈 질문을 나타내고 Options 속성을 통해 연결된 옵션을 노출합니다.
    • TriviaAnswer: 퀴즈 질문에 대한 응답으로 사용자가 선택한 옵션을 나타냅니다.
    • TriviaContext: Geek Quiz 애플리케이션의 Entity Framework 데이터베이스 컨텍스트를 나타냅니다. 이 클래스는 DContext 에서 파생되고 위에서 설명한 엔터티의 컬렉션을 나타내는 DbSet 속성을 노출합니다.
    • TriviaDatabaseInitializer:CreateDatabaseIfNotExists에서 상속하는 TriviaContext 클래스에 대한 Entity Framework 이니셜라이저 구현입니다. 이 클래스의 기본 동작은 데이터베이스가 없는 경우에만 데이터베이스를 만들고 Seed 메서드에 지정된 엔터티를 삽입하는 것입니다.
  6. Global.asax.cs 파일을 열고 다음 using 문을 추가합니다.

    using GeekQuiz.Models;
    
  7. Application_Start 메서드의 시작 부분에 다음 코드를 추가하여 TriviaDatabaseInitializer를 데이터베이스 이니셜라이저로 설정합니다.

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            System.Data.Entity.Database.SetInitializer(new TriviaDatabaseInitializer()); 
    
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
    
  8. 컨트롤러를 수정하여 인증된 사용자에 대한 액세스를 제한합니다. 이렇게 하려면 Controllers 폴더 내에서 HomeController.cs 파일을 열고 HomeController 클래스 정의에 Authorize 특성을 추가합니다.

    namespace GeekQuiz.Controllers
    {
        [Authorize]
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
    
            ...
        }
    }
    

    참고

    권한 부여 필터는 사용자가 인증되었는지 확인합니다. 사용자가 인증되지 않은 경우 작업을 호출하지 않고 HTTP 상태 코드 401(권한 없음)을 반환합니다. 필터를 전역적으로, 컨트롤러 수준 또는 개별 작업 수준에서 적용할 수 있습니다.

  9. 이제 웹 페이지 및 브랜딩의 레이아웃을 사용자 지정합니다. 이렇게 하려면 Views | 내에서 _Layout.cshtml 파일을 엽니다.내 ASP.NET 애플리케이션<괴짜 퀴즈로 바꿔서 폴더를 공유하고 타이틀> 요소의 콘텐츠를 업데이트합니다.

    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>@ViewBag.Title - Geek Quiz</title>
        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")
    
    </head>
    
  10. 동일한 파일에서 정보연락처 링크를 제거하고 링크의 이름을 Play로 변경하여 탐색 모음을 업데이트 합니다. 또한 애플리케이션 이름 링크의 이름을 Geek Quiz로 바꿉니다. 탐색 모음의 HTML은 다음 코드와 같습니다.

    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Geek Quiz", "Index", "Home", null, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Play", "Index", "Home")</li>
                </ul>
                @Html.Partial("_LoginPartial")
            </div>
        </div>
    </div>
    
  11. 내 ASP.NET 애플리케이션괴짜 퀴즈로 바꿔 레이아웃 페이지의 바닥글을 업데이트합니다. 이렇게 하려면 바닥글> 요소의< 내용을 강조 표시된 다음 코드로 바꿉다.

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - Geek Quiz</p>
        </footer>
    </div>
    

작업 2 - TriviaController 웹 API 만들기

이전 작업에서는 Geek 퀴즈 웹 애플리케이션의 초기 구조를 만들었습니다. 이제 퀴즈 데이터 모델과 상호 작용하고 다음 작업을 노출하는 간단한 Web API 서비스를 빌드합니다.

  • GET /api/trivia: 인증된 사용자가 답변할 퀴즈 목록에서 다음 질문을 검색합니다.
  • POST /api/trivia: 인증된 사용자가 지정한 퀴즈 답변을 저장합니다.

Visual Studio에서 제공하는 ASP.NET 스캐폴딩 도구를 사용하여 Web API 컨트롤러 클래스에 대한 기준을 만듭니다.

  1. App_Start 폴더 내에서 WebApiConfig.cs 파일을 엽니다. 이 파일은 경로가 Web API 컨트롤러 작업에 매핑되는 방법과 같은 Web API 서비스의 구성을 정의합니다.

  2. 파일의 시작 부분에 다음 using 문을 추가합니다.

    using Newtonsoft.Json.Serialization;
    
  3. Register 메서드에 강조 표시된 다음 코드를 추가하여 Web API 작업 메서드에서 검색한 JSON 데이터에 대한 포맷터를 전역적으로 구성합니다.

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
    
            // Use camel case for JSON data.
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    
            // Web API routes
            config.MapHttpAttributeRoutes();
    
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
    

    참고

    CamelCasePropertyNamesContractResolver는 속성 이름을 JavaScript의 속성 이름에 대한 일반적인 규칙인 낙타 대/소문자로 자동으로 변환합니다.

  4. 솔루션 탐색기GeekQuiz 프로젝트의 Controllers 폴더를 마우스 오른쪽 단추로 클릭하고 추가 | 를 선택합니다. 새 스캐폴드된 항목....

    새 스캐폴드된 항목

    새 스캐폴드된 항목 만들기

  5. 스캐폴드 추가 대화 상자의 왼쪽 창에서 공통 노드가 선택되어 있는지 확인합니다. 그런 다음 가운데 창에서 Web API 2 컨트롤러 - 빈 템플릿을 선택하고 추가를 클릭합니다.

    Web API 2 컨트롤러 빈 템플릿 선택

    Web API 2 컨트롤러 빈 템플릿 선택

    참고

    ASP.NET 스캐폴딩 은 ASP.NET 웹 애플리케이션을 위한 코드 생성 프레임워크입니다. Visual Studio 2013 MVC 및 Web API 프로젝트에 대해 미리 설치된 코드 생성기가 포함되어 있습니다. 표준 데이터 작업을 개발하는 데 필요한 시간을 줄이기 위해 데이터 모델과 상호 작용하는 코드를 빠르게 추가하려는 경우 프로젝트에서 스캐폴딩을 사용해야 합니다.

    또한 스캐폴딩 프로세스를 통해 필요한 모든 종속성이 프로젝트에 설치됩니다. 예를 들어 빈 ASP.NET 프로젝트로 시작한 다음 스캐폴딩을 사용하여 Web API 컨트롤러를 추가하는 경우 필요한 Web API NuGet 패키지 및 참조가 프로젝트에 자동으로 추가됩니다.

  6. 컨트롤러 추가 대화 상자의 컨트롤러 이름 텍스트 상자에 TriviaController를 입력하고 추가를 클릭합니다.

    퀴즈 컨트롤러 추가

    퀴즈 컨트롤러 추가

  7. 그런 다음 TriviaController.cs 파일이 빈 TriviaController 클래스를 포함하는 GeekQuiz 프로젝트의 Controllers 폴더에 추가됩니다. 파일의 시작 부분에 다음 using 문을 추가합니다.

    (코드 조각 - AspNetWebApiSpa - Ex1 - TriviaControllerUsings)

    using System.Data.Entity;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http.Description;
    using GeekQuiz.Models;
    
  8. TriviaController 클래스의 시작 부분에 다음 코드를 추가하여 컨트롤러에서 TriviaContext instance 정의, 초기화 및 삭제합니다.

    (코드 조각 - AspNetWebApiSpa - Ex1 - TriviaControllerContext)

    public class TriviaController : ApiController
    {
        private TriviaContext db = new TriviaContext();
    
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.db.Dispose();
            }
    
            base.Dispose(disposing);
        }
    }
    

    참고

    TriviaControllerDispose 메서드는 TriviaContext instance Dispose 메서드를 호출하므로 TriviaContext instance 삭제되거나 가비지 수집될 때 컨텍스트 개체에서 사용하는 모든 리소스가 해제됩니다. 여기에는 Entity Framework에서 연 모든 데이터베이스 연결 닫는 것이 포함됩니다.

  9. TriviaController 클래스의 끝에 다음 도우미 메서드를 추가합니다. 이 메서드는 지정된 사용자가 대답할 데이터베이스에서 다음 퀴즈 질문을 검색합니다.

    (코드 조각 - AspNetWebApiSpa - Ex1 - TriviaControllerNextQuestion)

    private async Task<TriviaQuestion> NextQuestionAsync(string userId)
    {
        var lastQuestionId = await this.db.TriviaAnswers
            .Where(a => a.UserId == userId)
            .GroupBy(a => a.QuestionId)
            .Select(g => new { QuestionId = g.Key, Count = g.Count() })
            .OrderByDescending(q => new { q.Count, QuestionId = q.QuestionId })
            .Select(q => q.QuestionId)
            .FirstOrDefaultAsync();
    
        var questionsCount = await this.db.TriviaQuestions.CountAsync();
    
        var nextQuestionId = (lastQuestionId % questionsCount) + 1;
        return await this.db.TriviaQuestions.FindAsync(CancellationToken.None, nextQuestionId);
    }
    
  10. TriviaController 클래스에 다음 Get 작업 메서드를 추가합니다. 이 작업 메서드는 이전 단계에서 정의된 NextQuestionAsync 도우미 메서드를 호출하여 인증된 사용자에 대한 다음 질문을 검색합니다.

    (코드 조각 - AspNetWebApiSpa - Ex1 - TriviaControllerGetAction)

    // GET api/Trivia
    [ResponseType(typeof(TriviaQuestion))]
    public async Task<IHttpActionResult> Get()
    {
        var userId = User.Identity.Name;
    
        TriviaQuestion nextQuestion = await this.NextQuestionAsync(userId);
    
        if (nextQuestion == null)
        {
            return this.NotFound();
        }
    
        return this.Ok(nextQuestion);
    }
    
  11. TriviaController 클래스의 끝에 다음 도우미 메서드를 추가합니다. 이 메서드는 데이터베이스에 지정된 답변을 저장하고 대답이 올바른지 여부를 나타내는 부울 값을 반환합니다.

    (코드 조각 - AspNetWebApiSpa - Ex1 - TriviaControllerStoreAsync)

    private async Task<bool> StoreAsync(TriviaAnswer answer)
    {
        this.db.TriviaAnswers.Add(answer);
    
        await this.db.SaveChangesAsync();
        var selectedOption = await this.db.TriviaOptions.FirstOrDefaultAsync(o => o.Id == answer.OptionId
            && o.QuestionId == answer.QuestionId);
    
        return selectedOption.IsCorrect;
    }
    
  12. TriviaController 클래스에 다음 Post 작업 메서드를 추가합니다. 이 작업 메서드는 인증된 사용자에게 답변을 연결하고 StoreAsync 도우미 메서드를 호출합니다. 그런 다음 도우미 메서드에서 반환된 부울 값을 사용하여 응답을 보냅니다.

    (코드 조각 - AspNetWebApiSpa - Ex1 - TriviaControllerPostAction)

    // POST api/Trivia
    [ResponseType(typeof(TriviaAnswer))]
    public async Task<IHttpActionResult> Post(TriviaAnswer answer)
    {
        if (!ModelState.IsValid)
        {
            return this.BadRequest(this.ModelState);
        }
    
        answer.UserId = User.Identity.Name;
    
        var isCorrect = await this.StoreAsync(answer);
        return this.Ok<bool>(isCorrect);
    }
    
  13. TriviaController 클래스 정의에 Authorize 특성을 추가하여 인증된 사용자에 대한 액세스를 제한하도록 Web API 컨트롤러를 수정합니다.

    [Authorize]
    public class TriviaController : ApiController
    {
        ...
    }
    

작업 3 – 솔루션 실행

이 작업에서는 이전 작업에서 빌드한 Web API 서비스가 예상대로 작동하는지 확인합니다. 인터넷 Explorer F12 개발자 도구를 사용하여 네트워크 트래픽을 캡처하고 Web API 서비스의 전체 응답을 검사합니다.

참고

Visual Studio 도구 모음의 시작 단추에서 인터넷 Explorer 선택되어 있는지 확인합니다.

인터넷 Explorer 옵션

  1. F5 키를 눌러 솔루션을 실행합니다. 로그인 페이지가 브라우저에 표시됩니다.

    참고

    애플리케이션이 시작되면 기본 MVC 경로가 트리거되며 기본적으로 HomeController 클래스의 인덱스 작업에 매핑됩니다. HomeController는 인증된 사용자로 제한되고(연습 1에서 Authorize 특성으로 해당 클래스를 데코레이트했음을 기억함) 아직 인증된 사용자가 없으므로 애플리케이션은 원래 요청을 로그인 페이지로 리디렉션합니다.

    솔루션 실행

    솔루션을 실행합니다.

  2. 등록을 클릭하여 새 사용자를 만듭니다.

    새 사용자 등록

    새 사용자 등록

  3. 등록 페이지에서 사용자 이름암호를 입력한 다음 등록을 클릭합니다.

    등록 페이지

    등록 페이지

  4. 애플리케이션은 새 계정을 등록하고 사용자가 인증되고 홈페이지로 다시 리디렉션됩니다.

    사용자가 인증된

    사용자가 인증됨

  5. 브라우저에서 F12 키를 눌러 개발자 도구 패널을 엽니다. Ctrl + 4를 누르거나 네트워크 아이콘을 클릭한 다음 녹색 화살표 단추를 클릭하여 네트워크 트래픽 캡처를 시작합니다.

    Web API 네트워크 캡처 시작

    Web API 네트워크 캡처 시작

  6. 브라우저 주소 표시줄의 URL에 api/trivia 를 추가합니다. 이제 TriviaControllerGet 작업 메서드에서 응답의 세부 정보를 검사합니다.

    Web API를 통해 다음 질문 데이터 검색 Web API

    Web API를 통해 다음 질문 데이터 검색

    참고

    다운로드가 완료되면 다운로드한 파일을 사용하여 작업을 수행하라는 메시지가 표시됩니다. 개발자 도구 창을 통해 응답 콘텐츠를 watch 수 있도록 대화 상자를 열어 둡니다.

  7. 이제 응답 본문을 검사합니다. 이렇게 하려면 세부 정보 탭을 클릭한 다음 응답 본문을 클릭합니다. 다운로드한 데이터가 TriviaQuestion 클래스에 해당하는 속성 옵션(TriviaOption 개체 목록), ID제목이 있는 개체임을 검사 수 있습니다.

    Web API 응답 본문 보기

    Web API 응답 본문 보기

  8. Visual Studio로 돌아가기 Shift + F5를 눌러 디버깅을 중지합니다.

연습 2: SPA 인터페이스 만들기

이 연습에서는 먼저 AngularJS를 사용하여 Single-Page 애플리케이션 상호 작용에 중점을 두고 Geek 퀴즈의 웹 프런트 엔드 부분을 빌드합니다. 그런 다음 CSS3을 사용하여 사용자 환경을 개선하여 풍부한 애니메이션을 수행하고 한 질문에서 다음 질문으로 전환할 때 컨텍스트 전환의 시각적 효과를 제공합니다.

작업 1 – AngularJS를 사용하여 SPA 인터페이스 만들기

이 작업에서는 AngularJS 를 사용하여 Geek 퀴즈 애플리케이션의 클라이언트 쪽을 구현합니다. AngularJS 는 MVC( Model-View-Controller ) 기능을 사용하여 브라우저 기반 애플리케이션을 보강하여 개발 및 테스트를 용이하게 하는 오픈 소스 JavaScript 프레임워크입니다.

먼저 Visual Studio의 패키지 관리자 콘솔에서 AngularJS를 설치합니다. 그런 다음, AngularJS 템플릿 엔진을 사용하여 퀴즈 질문과 답변을 렌더링하는 Geek 퀴즈 앱의 동작과 보기를 제공하는 컨트롤러를 만듭니다.

참고

AngularJS에 대한 자세한 내용은 [http://angularjs.org/](http://angularjs.org/)를 참조하세요.

  1. Visual Studio Express 2013 for Web을 열고 Source/Ex2-CreatingASPAInterface/Begin 폴더에 있는 GeekQuiz.sln 솔루션을 엽니다. 또는 이전 연습에서 얻은 솔루션을 계속 진행할 수 있습니다.

  2. 도구>NuGet 패키지 관리자에서 패키지 관리자콘솔을 엽니다. 다음 명령을 입력하여 AngularJS.Core NuGet 패키지를 설치합니다.

    Install-Package AngularJS.Core
    
  3. 솔루션 탐색기GeekQuiz 프로젝트의 Scripts 폴더를 마우스 오른쪽 단추로 클릭하고 추가 | 를 선택합니다. 새 폴더. 폴더 의 이름을 지정하고 Enter 키를 누릅니다.

  4. 방금 만든 폴더를 마우스 오른쪽 단추로 클릭하고 추가 | JavaScript 파일.

    새 JavaScript 파일 만들기

    새 JavaScript 파일 만들기

  5. 항목 이름 지정 대화 상자의 항목 이름 텍스트 상자에 quiz-controller를 입력하고 확인을 클릭합니다.

    새 JavaScript 파일 이름 지정

    새 JavaScript 파일 이름 지정

  6. quiz-controller.js 파일에서 다음 코드를 추가하여 AngularJS QuizCtrl 컨트롤러를 선언하고 초기화합니다.

    (코드 조각 - AspNetWebApiSpa - Ex2 - AngularQuizController)

    angular.module('QuizApp', [])
        .controller('QuizCtrl', function ($scope, $http) {
            $scope.answered = false;
            $scope.title = "loading question...";
            $scope.options = [];
            $scope.correctAnswer = false;
            $scope.working = false;
    
            $scope.answer = function () {
                return $scope.correctAnswer ? 'correct' : 'incorrect';
            };
        });
    

    참고

    QuizCtrl 컨트롤러의 생성자 함수에는 $scope 라는 삽입 가능한 매개 변수가 예상됩니다. $scope 개체에 속성을 연결하여 생성자 함수에서 scope 초기 상태를 설정해야 합니다. 속성은 보기 모델을 포함하며 컨트롤러가 등록될 때 템플릿에 액세스할 수 있습니다.

    QuizCtrl 컨트롤러는 QuizApp이라는 모듈 내에 정의됩니다. 모듈은 애플리케이션을 별도의 구성 요소로 분리할 수 있는 작업 단위입니다. 모듈 사용의 기본 장점은 코드가 더 쉽게 이해하고 단위 테스트, 재사용 가능성 및 유지 관리를 용이하게 한다는 것입니다.

  7. 이제 보기에서 트리거된 이벤트에 반응하기 위해 scope 동작을 추가합니다. QuizCtrl 컨트롤러 끝에 다음 코드를 추가하여 $scope 개체에서 nextQuestion 함수를 정의합니다.

    (코드 조각 - AspNetWebApiSpa - Ex2 - AngularQuizControllerNextQuestion)

    .controller('QuizCtrl', function ($scope, $http) { 
        ...
    
        $scope.nextQuestion = function () {
            $scope.working = true;
            $scope.answered = false;
            $scope.title = "loading question...";
            $scope.options = [];
    
            $http.get("/api/trivia").success(function (data, status, headers, config) {
                $scope.options = data.options;
                $scope.title = data.title;
                $scope.answered = false;
                $scope.working = false;
            }).error(function (data, status, headers, config) {
                $scope.title = "Oops... something went wrong";
                $scope.working = false;
            });
        };
    };
    

    참고

    이 함수는 이전 연습에서 만든 Trivia Web API에서 다음 질문을 검색하고 질문 데이터를 $scope 개체에 연결합니다.

  8. QuizCtrl 컨트롤러 끝에 다음 코드를 삽입하여 $scope 개체에서 sendAnswer 함수를 정의합니다.

    (코드 조각 - AspNetWebApiSpa - Ex2 - AngularQuizControllerSendAnswer)

    .controller('QuizCtrl', function ($scope, $http) { 
        ...
    
        $scope.sendAnswer = function (option) {
            $scope.working = true;
            $scope.answered = true;
    
            $http.post('/api/trivia', { 'questionId': option.questionId, 'optionId': option.id }).success(function (data, status, headers, config) {
                $scope.correctAnswer = (data === true);
                $scope.working = false;
            }).error(function (data, status, headers, config) {
                $scope.title = "Oops... something went wrong";
                $scope.working = false;
            });
        };
    };
    

    참고

    이 함수는 사용자가 선택한 답변을 Trivia Web API로 보내고 결과를 $scope 개체에 저장합니다.

    위의 nextQuestionsendAnswer 함수는 AngularJS $http 개체를 사용하여 브라우저에서 XMLHttpRequest JavaScript 개체를 통해 Web API와의 통신을 추상화합니다. AngularJS는 RESTful API를 통해 리소스에 대해 CRUD 작업을 수행하기 위해 더 높은 수준의 추상화가 제공되는 다른 서비스를 지원합니다. AngularJS $resource 개체에는 $http 개체와 상호 작용할 필요 없이 상위 수준 동작을 제공하는 작업 메서드가 있습니다. CRUD 모델이 필요한 시나리오에서 $resource 개체를 사용하는 것이 좋습니다(예: 정보, $resource 설명서 참조).

  9. 다음 단계는 퀴즈의 보기를 정의하는 AngularJS 템플릿을 만드는 것입니다. 이렇게 하려면 Views | 내에서 Index.cshtml 파일을 엽니다. 폴더 및 콘텐츠를 다음 코드로 바꿉 있습니다.

    (코드 조각 - AspNetWebApiSpa - Ex2 - GeekQuizView)

    @{
        ViewBag.Title = "Play";
    }
    
    <div id="bodyContainer" ng-app="QuizApp">
        <section id="content">
            <div class="container" >
                <div class="row">
                    <div class="flip-container text-center col-md-12" ng-controller="QuizCtrl" ng-init="nextQuestion()">
                        <div class="back" ng-class="{flip: answered, correct: correctAnswer, incorrect:!correctAnswer}">
                            <p class="lead">{{answer()}}</p>
                            <p>
                                <button class="btn btn-info btn-lg next option" ng-click="nextQuestion()" ng-disabled="working">Next Question</button>
                            </p>
                        </div>
                        <div class="front" ng-class="{flip: answered}">
                            <p class="lead">{{title}}</p>
                            <div class="row text-center">
                                <button class="btn btn-info btn-lg option" ng-repeat="option in options" ng-click="sendAnswer(option)" ng-disabled="working">{{option.title}}</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </div>
    
    @section scripts {
        @Scripts.Render("~/Scripts/angular.js")
        @Scripts.Render("~/Scripts/app/quiz-controller.js")
    }
    

    참고

    AngularJS 템플릿은 모델 및 컨트롤러의 정보를 사용하여 정적 태그를 사용자가 브라우저에서 보는 동적 보기로 변환하는 선언적 사양입니다. 다음은 템플릿에서 사용할 수 있는 AngularJS 요소 및 요소 특성의 예입니다.

    • ng-app 지시문은 AngularJS에 애플리케이션의 루트 요소를 나타내는 DOM 요소를 알려줍니다.
    • ng-controller 지시문은 지시문이 선언된 지점에서 컨트롤러를 DOM에 연결합니다.
    • 중괄호 표기법 {{ }}은 컨트롤러에 정의된 scope 속성에 대한 바인딩을 나타냅니다.
    • ng-click 지시문은 사용자 클릭에 대한 응답으로 scope 정의된 함수를 호출하는 데 사용됩니다.
  10. Content 폴더 내에서 Site.css 파일을 열고 파일 끝에 강조 표시된 다음 스타일을 추가하여 퀴즈 보기의 모양과 느낌을 제공합니다.

    (코드 조각 - AspNetWebApiSpa - Ex2 - GeekQuizStyles)

    .validation-summary-valid {
         display: none;
    }
    
    /* Geek Quiz styles */
    .flip-container .back,
    .flip-container .front {
         border: 5px solid #00bcf2;
         padding-bottom: 30px;
         padding-top: 30px;
    }
    
    #content {
        position:relative;
        background:#fff;
        padding:50px 0 0 0;
    }
    
    .option {
         width:140px;
         margin: 5px;
    }
    
    div.correct p {
         color: green;
    }
    
    div.incorrect p {
         color: red;
    }
    
    .btn {
         border-radius: 0;
    }
    
    .flip-container div.front, .flip-container div.back.flip {
        display: block;
    }
    
    .flip-container div.front.flip, .flip-container div.back {
        display: none;
    }
    

작업 2 – 솔루션 실행

이 작업에서는 AngularJS로 빌드한 새 사용자 인터페이스를 사용하여 솔루션을 실행하여 몇 가지 퀴즈 질문에 답변합니다.

  1. F5 키를 눌러 솔루션을 실행합니다.

  2. 새 사용자 계정을 등록합니다. 이렇게 하려면 연습 1, 작업 3에 설명된 등록 단계를 수행합니다.

    참고

    이전 연습에서 솔루션을 사용하는 경우 이전에 만든 사용자 계정으로 로그인할 수 있습니다.

  3. 퀴즈의 첫 번째 질문을 보여 주는 페이지가 표시됩니다. 옵션 중 하나를 클릭하여 질문에 대답합니다. 이렇게 하면 이전에 정의된 sendAnswer 함수가 트리거되며, 이 함수는 선택한 옵션을 Trivia Web API로 보냅니다.

    질문에 답변

    질문 답변

  4. 단추 중 하나를 클릭하면 답변이 나타납니다. 다음 질문을 클릭하여 다음 질문을 표시합니다. 그러면 컨트롤러에 정의된 nextQuestion 함수가 트리거됩니다.

    다음 질문 요청

    다음 질문 요청

  5. 다음 질문이 나타납니다. 원하는 횟수만큼 질문에 계속 답변하세요. 모든 질문을 완료한 후 첫 번째 질문으로 돌아가야 합니다.

    또 다른 질문

    다음 질문

  6. Visual Studio로 돌아가기 Shift + F5를 눌러 디버깅을 중지합니다.

작업 3 - CSS3을 사용하여 대칭 이동 애니메이션 만들기

이 작업에서는 CSS3 속성을 사용하여 질문에 대한 답변과 다음 질문을 검색할 때 대칭 이동 효과를 추가하여 풍부한 애니메이션을 수행합니다.

  1. 솔루션 탐색기GeekQuiz 프로젝트의 Content 폴더를 마우스 오른쪽 단추로 클릭하고 추가 | 기존 항목....

    콘텐츠 폴더에 기존 항목 추가컨텐

    콘텐츠 폴더에 기존 항목 추가

  2. 기존 항목 추가 대화 상자에서 원본/자산 폴더로 이동하고 Flip.css를 선택합니다. 추가를 클릭합니다.

    자산에서 Flip.css 파일 추가자산에서

    자산에서 Flip.css 파일 추가

  3. 방금 추가한 Flip.css 파일을 열고 해당 콘텐츠를 검사합니다.

  4. 대칭 이동 변환 주석을 찾습니다. 해당 주석 아래의 스타일은 CSS 큐브 뷰rotateY 변환을 사용하여 "카드 대칭 이동" 효과를 생성합니다.

    /* flip transformation */
    .flip-container div.front {
        -moz-transform: perspective(2000px) rotateY(0deg);
        -webkit-transform: perspective(2000px) rotateY(0deg);
        -o-transform: perspective(2000px) rotateY(0deg);
        transform: perspective(2000px) rotateY(0deg);
    }
    
        .flip-container div.front.flip {
            -moz-transform: perspective(2000px) rotateY(179.9deg);
            -webkit-transform: perspective(2000px) rotateY(179.9deg);
            -o-transform: perspective(2000px) rotateY(179.9deg);
            transform: perspective(2000px) rotateY(179.9deg);
        }
    
    .flip-container div.back {
        -moz-transform: perspective(2000px) rotateY(-180deg);
        -webkit-transform: perspective(2000px) rotateY(-180deg);
        -o-transform: perspective(2000px) rotateY(-180deg);
        transform: perspective(2000px) rotateY(-180deg);
    }
    
        .flip-container div.back.flip {
            -moz-transform: perspective(2000px) rotateY(0deg);
            -webkit-transform: perspective(2000px) rotateY(0deg);
            -ms-transform: perspective(2000px) rotateY(0);
            -o-transform: perspective(2000px) rotateY(0);
            transform: perspective(2000px) rotateY(0);
        }
    
  5. 대칭 이동 주석이 있는 동안 창의 뒤로 숨기기를 찾습니다. 아래의 주석 스타일은 백페이스 표시 유형 CSS 속성을 김으로 설정하여 뷰어와 마주할 때 얼굴의 뒷면을 숨깁니다.

    /* hide back of pane during flip */
    .front, .back {
        -moz-backface-visibility: hidden;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
    }
    
  6. App_Start 폴더 내에서 BundleConfig.cs 파일을 열고 "~/Content/css" 스타일 번들에서 Flip.css 파일에 대한 참조를 추가합니다.

    bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/Content/bootstrap.css",
        "~/Content/site.css",
        "~/Content/Flip.css"));
    
  7. F5 키를 눌러 솔루션을 실행하고 자격 증명으로 로그인합니다.

  8. 옵션 중 하나를 클릭하여 질문에 대답합니다. 보기 간에 전환할 때 대칭 이동 효과를 확인합니다.

    대칭 이동 효과로 질문에 답변 대칭

    대칭 이동 효과로 질문 답변

  9. 다음 질문을 클릭하여 다음 질문을 검색합니다. 대칭 이동 효과가 다시 나타납니다.

    대칭 이동 효과로 다음 질문 검색 대칭 이동 검색

    대칭 이동 효과로 다음 질문 검색


요약

이 실습 랩을 완료하여 다음을 수행하는 방법을 배웠습니다.

  • ASP.NET 스캐폴딩을 사용하여 ASP.NET Web API 컨트롤러 만들기
  • Web API 가져오기 작업을 구현하여 다음 퀴즈 질문 검색
  • 퀴즈 답변을 저장하는 Web API Post 작업 구현
  • Visual Studio 패키지 관리자 콘솔에서 AngularJS 설치
  • AngularJS 템플릿 및 컨트롤러 구현
  • CSS3 전환을 사용하여 애니메이션 효과 수행