Partilhar via


Laboratório Prático: Construa uma Aplicação de Página Única (SPA) com ASP.NET API Web e Angular.js

pela equipa Web Camps

Descarregar o Kit de Treino Web Camps

Este laboratório prático mostra-lhe como construir uma Aplicação de Página Única (SPA) com ASP.NET Web API e Angular.js para ASP.NET 4.x.

Neste laboratório prático, irá aproveitar essas tecnologias para implementar o Geek Quiz, um site de perguntas e respostas baseado no conceito SPA. Primeiro, irá implementar a camada de serviço com ASP.NET API Web para expor os endpoints necessários para recuperar as perguntas do questionário e armazenar as respostas. Depois, vais construir uma interface rica e responsiva usando efeitos de transformação em AngularJS e CSS3.

Nas aplicações web tradicionais, o cliente (navegador) inicia a comunicação com o servidor solicitando uma página. O servidor processa então o pedido e envia o HTML da página para o cliente. Em interações subsequentes com a página – por exemplo, o utilizador navega até um link ou submete um formulário com dados – é enviado um novo pedido ao servidor, e o fluxo recomeça: o servidor processa o pedido e envia uma nova página para o navegador em resposta à nova ação solicitada pelo cliente.

Em Aplicações Single-Page (SPAs), toda a página é carregada no navegador após o pedido inicial, mas as interações subsequentes ocorrem através de requisições Ajax. Isto significa que o navegador tem de atualizar apenas a parte da página que mudou; Não é necessário recarregar toda a página. A abordagem SPA reduz o tempo que a aplicação demora a responder às ações do utilizador, resultando numa experiência mais fluida.

A arquitetura de um SPA envolve certos desafios que não existem nas aplicações web tradicionais. No entanto, tecnologias emergentes como ASP.NET Web API, frameworks JavaScript como o AngularJS e novas funcionalidades de estilo fornecidas pelo CSS3 tornam muito fácil o design e construção de SPAs.

Todo o código de exemplo e excertos estão incluídos no Kit de Formação dos Web Camps, disponível em https://aka.ms/webcamps-training-kit.

Descrição geral

Objetivos

Neste laboratório prático, vai aprender como:

  • Criar um serviço ASP.NET Web API para enviar e receber dados JSON
  • Crie uma interface responsiva usando AngularJS
  • Melhore a experiência da interface com transformações em CSS3

Pré-requisitos

O seguinte é necessário para completar este laboratório prático:

Configuração

Para realizar os exercícios neste laboratório prático, terá de preparar primeiro o seu ambiente.

  1. Abra o Explorador do Windows e navegue até à pasta Source do laboratório.
  2. Clique com o botão direito em Setup.cmd e selecione Executar como administrador para iniciar o processo de configuração que irá configurar o seu ambiente e instalar os excertos de código do Visual Studio para este laboratório.
  3. Se aparecer a caixa de diálogo Controlo da Conta de Utilizador, confirme a ação para prosseguir.

Observação

Certifica-te de que verificaste todas as dependências deste laboratório antes de executares a configuração.

Utilização de Fragmentos de Código

Ao longo do documento do laboratório, ser-se-á instruído a inserir blocos de código. Para sua conveniência, a maior parte deste código é fornecida como Excertos de Código do Visual Studio, aos quais pode aceder dentro do Visual Studio 2013 para evitar ter de o adicionar manualmente.

Observação

Cada exercício é acompanhado por uma solução inicial localizada na pasta Begin do exercício, que permite seguir cada exercício independentemente dos outros. Por favor, tenha em atenção que os excertos de código adicionados durante um exercício estão em falta nestas soluções iniciais e podem não funcionar até completar o exercício. Dentro do código-fonte de um exercício, encontrará também uma pasta End contendo uma solução Visual Studio com o código resultante da conclusão dos passos do exercício correspondente. Pode usar estas soluções como orientação caso precise de ajuda adicional durante este laboratório prático.


Exercícios

Este laboratório prático inclui os seguintes exercícios:

  1. Criação de uma API Web
  2. Criação de uma Interface SPA

Tempo estimado para completar este laboratório: 60 minutos

Observação

Quando iniciar o Visual Studio pela primeira vez, deve selecionar uma das coleções de definições pré-definidas. Cada coleção pré-definida é concebida para corresponder a um estilo de desenvolvimento particular e determina layouts de janelas, comportamento do editor, excertos de código IntelliSense e opções de caixas de diálogo. Os procedimentos deste laboratório descrevem as ações necessárias para realizar uma determinada tarefa no Visual Studio ao utilizar a coleção General Development Settings . Se escolher uma coleção de definições diferente para o seu ambiente de desenvolvimento, pode haver diferenças nos passos que deve considerar.

Exercício 1: Criação de uma API Web

Uma das partes-chave de um SPA é a camada de serviço. É responsável por processar as chamadas Ajax enviadas pela interface e por devolver os dados em resposta a essa chamada. Os dados recuperados devem ser apresentados num formato legível por máquina para serem analisados e consumidos pelo cliente.

A framework Web API faz parte da ASP.NET Stack e foi concebida para facilitar a implementação de serviços HTTP, geralmente enviando e recebendo dados em formato JSON ou XML através de uma API RESTful. Neste exercício, irá criar o site para alojar a aplicação Geek Quiz e depois implementar o serviço de back-end para expor e persistir os dados do questionário usando ASP.NET Web API.

Tarefa 1 – Criar o Projeto Inicial para o Geek Quiz

Nesta tarefa, começará a criar um novo projeto ASP.NET MVC com suporte para ASP.NET Web API, baseado no tipo de projeto One ASP.NET que vem com o Visual Studio. Um ASP.NET unifica todas as tecnologias ASP.NET e dá-te a opção de as misturar e combinar conforme desejar. Depois adicionará as classes modelo do Entity Framework e o inicializador da base de dados para inserir as perguntas do questionário.

  1. Abra o Visual Studio Express 2013 para Web e selecione Ficheiro | Novo projeto... para começar uma nova solução.

    Criar um Novo Projeto

    Criar um Novo Projeto

  2. Na caixa de diálogo Novo Projeto , selecione Aplicação Web ASP.NET no Separador Visual C# | Web. Certifique-se de que está selecionado o .NET Framework 4.5, nomeie-o como GeekQuiz, escolha uma Localização e clique em OK.

    Criar um novo projeto de Aplicação Web ASP.NET

    Criar um novo projeto de Aplicação Web ASP.NET

  3. Na caixa de diálogo do Projeto Novo ASP.NET , selecione o modelo MVC e selecione a opção Web API . Além disso, certifique-se de que a opção de Autenticação está definida como Contas de Utilizador Individuais. Clique em OK para continuar.

    Criar um novo projeto com o modelo MVC, incluindo componentes Web API

    Criar um novo projeto com o modelo MVC, incluindo componentes Web API

  4. No Explorador de Soluções, clique com o botão direito na pasta Modelos do projeto GeekQuiz e selecione Adicionar | Item Existente....

    Adicionar um item existente

    Adicionar um item existente

  5. Na caixa de diálogo Adicionar Item Existente , navegue até à pasta Source/Assets/Models e selecione todos os ficheiros. Clique em Adicionar.

    Adicionar os recursos do modelo

    Adição dos recursos do modelo

    Observação

    Ao adicionar estes ficheiros, está a adicionar o modelo de dados, o contexto da base de dados do Entity Framework e o inicializador da base de dados para a aplicação Geek Quiz.

    Entity Framework (EF) é um mapeador objeto-relacional (ORM) que permite criar aplicações de acesso a dados programando com um modelo conceptual de aplicação, em vez de programar diretamente usando um esquema de armazenamento relacional. Pode saber mais sobre o Entity Framework aqui.

    Segue-se uma descrição das aulas que acabou de adicionar:

    • TriviaOption: representa uma única opção associada a uma pergunta de quiz
    • TriviaPergunta: representa uma pergunta de quiz e expõe as opções associadas através da propriedade Opções
    • TriviaResposta: representa a opção selecionada pelo utilizador em resposta a uma pergunta de questionário
    • TriviaContext: representa o contexto da base de dados do Entity Framework da aplicação Geek Quiz. Esta classe deriva do DContext e expõe propriedades do DbSet que representam coleções das entidades descritas acima.
    • TriviaDatabaseInitializer: a implementação do inicializador Entity Framework para a classe TriviaContext , que herda de CreateDatabaseIfNotExists. O comportamento padrão desta classe é criar a base de dados apenas se esta não existir, inserindo as entidades especificadas no método Seed .
  6. Abra o ficheiro Global.asax.cs e adicione a seguinte instrução usando .

    using GeekQuiz.Models;
    
  7. Adicione o seguinte código no início do método Application_Start para definir o TriviaDatabaseInitializer como inicializador da base de dados.

    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. Modificar o controlador Home para restringir o acesso a utilizadores autenticados. Para isso, abra o ficheiro HomeController.cs dentro da pasta Controllers e adicione o atributo Authorize à definição da classe HomeController .

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

    Observação

    O filtro Autorizar verifica se o utilizador está autenticado. Se o utilizador não estiver autenticado, devolve o código de estado HTTP 401 (Não autorizado) sem invocar a ação. Pode aplicar o filtro globalmente, ao nível do controlador ou ao nível das ações individuais.

  9. Agora irá personalizar o layout das páginas web e a imagem da marca. Para isso, abra o ficheiro _Layout.cshtml dentro da pasta Views | Shared e atualize o conteúdo do <title> substituindo a Minha Aplicação ASP.NET por Geek Quiz.

    <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. No mesmo ficheiro, atualize a barra de navegação removendo os links Sobre e Contacto e renomeando o link Home para Play. Além disso, renomeie o link do nome da Aplicação para Geek Quiz. O HTML da barra de navegação deve assemelhar-se ao seguinte código.

    <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. Atualize o rodapé da página de layout substituindo Minha Aplicação ASP.NET por Geek Quiz. Para isso, substitua o conteúdo do <elemento de> rodapé pelo código destacado a seguir.

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

Tarefa 2 – Criar a API Web do TriviaController

Na tarefa anterior, criou a estrutura inicial da aplicação web Geek Quiz. Agora irá construir um serviço simples de API Web que interage com o modelo de dados do questionário e expõe as seguintes ações:

  • GET /api/trivia: Recupera a próxima pergunta da lista de questionários para ser respondida pelo utilizador autenticado.
  • POST /api/trivia: Armazena a resposta do questionário especificada pelo utilizador autenticado.

Irá utilizar as ferramentas ASP.NET Scaffolding fornecidas pelo Visual Studio para criar a base para a classe controlador da Web API.

  1. Abre o ficheiro WebApiConfig.cs dentro da pasta App_Start . Este ficheiro define a configuração do serviço Web API, tal como as rotas são mapeadas para as ações do controlador Web API.

  2. Adicione a seguinte instrução "using" no início do ficheiro.

    using Newtonsoft.Json.Serialization;
    
  3. Adicione o seguinte código destacado ao método Register para configurar globalmente o formatador dos dados JSON recuperados pelos métodos de ação da Web API.

    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 }
            );
        }
    }
    

    Observação

    O CamelCasePropertyNamesContractResolver converte automaticamente nomes de propriedades para camel case, que é a convenção geral para nomes de propriedades em JavaScript.

  4. No Explorador de Soluções, clique com o botão direito na pasta Controladores do projeto GeekQuiz e selecione Adicionar | Novo Item Andaimado....

    Criar um novo item estruturado

    Criação de um novo item com andaimes

  5. Na caixa de diálogo Adicionar Andaime, certifique-se de que o nó Comum está selecionado no painel esquerdo. Depois, selecione o modelo Web API 2 Controller - Vazio no painel central e clique em Adicionar.

    Selecionar o modelo de Controlador Vazio da API Web 2

    Selecionar o modelo vazio do controlador Web API 2

    Observação

    ASP.NET Scaffolding é uma estrutura de geração de código para ASP.NET aplicações Web. O Visual Studio 2013 inclui geradores de código pré-instalados para projetos MVC e Web API. Deve usar andaimes no seu projeto quando quiser adicionar rapidamente código que interaja com modelos de dados para reduzir o tempo necessário para desenvolver operações padrão de dados.

    O processo de andaime também garante que todas as dependências necessárias são instaladas no projeto. Por exemplo, se começar com um projeto de ASP.NET vazio e depois usar andaimes para adicionar um controlador da Web API, os pacotes e referências NuGet da Web API necessários são automaticamente adicionados ao seu projeto.

  6. Na caixa de diálogo Adicionar Controlador , escreva TriviaController na caixa de texto do nome do Controlador e clique em Adicionar.

    Adicionar o Controlador de Perguntas

    Adição do Controlador de Perguntas

  7. O ficheiro TriviaController.cs é então adicionado à pasta Controllers do projeto GeekQuiz , contendo uma classe TriviaController vazia. Adicione as seguintes diretivas de uso no início do ficheiro.

    (Excerto de Código - AspNetWebApiSpa - Ex1 - TriviaControllerUsings)

    using System.Data.Entity;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http.Description;
    using GeekQuiz.Models;
    
  8. Adicione o seguinte código no início da classe TriviaController para definir, inicializar e eliminar a instância TriviaContext no controlador.

    (Excerto de Código - 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);
        }
    }
    

    Observação

    O método Dispose do TriviaController invoca o método Dispose da instância TriviaContext , que garante que todos os recursos usados pelo objeto de contexto são libertados quando a instância do TriviaContext é descartada ou recolhida no lixo. Isto inclui o encerramento de todas as ligações à base de dados abertas pelo Entity Framework.

  9. Adicione o seguinte método auxiliar no final da classe TriviaControler . Este método recupera a seguinte pergunta do quiz da base de dados para ser respondida pelo utilizador especificado.

    (Excerto de Código - 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. Adicione o seguinte método de ação Get à classe TriviaControler . Este método de ação chama o método helper NextQuestionAsync definido no passo anterior para recuperar a próxima pergunta para o utilizador autenticado.

    (Excerto de Código - 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. Adicione o seguinte método auxiliar no final da classe TriviaControler . Este método armazena a resposta especificada na base de dados e devolve um valor booleano indicando se a resposta está correta ou não.

    (Excerto de Código - 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. Adicione o seguinte método Post action à classe TriviaControler . Este método de ação associa a resposta ao utilizador autenticado e chama o método helper StoreAsync . Depois, envia uma resposta com o valor booleano devolvido pelo método auxiliar.

    (Excerto de Código - 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. Modificar o controlador Web API para restringir o acesso a utilizadores autenticados, adicionando o atributo Authorize à definição da classe TriviaControler .

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

Tarefa 3 – Executar a Solução

Nesta tarefa, irá verificar se o serviço Web API que construiu na tarefa anterior está a funcionar como esperado. Utilizará as Ferramentas de Desenvolvimento do Internet Explorer F12 para captar o tráfego de rede e inspecionar a resposta completa do serviço Web API.

Observação

Certifique-se de que o Internet Explorer está selecionado no botão Iniciar localizado na barra de ferramentas do Visual Studio.

Opção Internet Explorer

  1. Pressiona F5 para executar a solução. A página de Início de Sessão deve aparecer no navegador.

    Observação

    Quando a aplicação inicia, a rota padrão do MVC é ativada, sendo mapeada por padrão para a ação Index da classe HomeControlador. Como o HomeController está restrito a utilizadores autenticados (lembre-se que decorou essa classe com o atributo Authorize no Exercício 1) e ainda não há utilizador autenticado, a aplicação redireciona o pedido original para a página de login.

    Executar a solução

    Execução da solução

  2. Clique em Registar para criar um novo utilizador.

    Registar um novo utilizador

    Registar um novo utilizador

  3. Na página de Registo , introduza um Nome de Utilizador e uma Palavra-passe, e depois clique em Registar.

    Página de registo

    Página de registo

  4. A aplicação regista a nova conta e o utilizador é autenticado e redirecionado de volta para a página inicial.

    Utilizador é autenticado

    O utilizador é autenticado

  5. No navegador, pressione F12 para abrir o painel de Ferramentas para Desenvolvedores . Pressione CTRL + 4 ou clique no ícone de rede , e depois clique no botão de seta verde para começar a captar o tráfego de rede.

    Iniciar captura de rede Web API

    Iniciar a captura de redes Web API

  6. Adicione API/curiosidades à URL na barra de endereços do navegador. Agora irá inspecionar os detalhes da resposta do método de ação Get no TriviaController.

    Recuperar os dados da próxima pergunta através da Web API

    Recuperação dos dados da próxima pergunta através da Web API

    Observação

    Quando o download terminar, ser-se-á solicitado a fazer uma ação com o ficheiro descarregado. Deixa a caixa de diálogo aberta para poderes ver o conteúdo das respostas através da janela da Ferramenta de Desenvolvedores.

  7. Agora inspecionará o conteúdo da resposta. Para isso, clique no separador Detalhes e depois em Corpo da Resposta. Pode verificar se os dados descarregados são um objeto com as opções de propriedades (que é uma lista de objetos TriviaOption ), id e título que correspondem à classe TriviaQuestion .

    Visualização do Corpo de Resposta da Web API

    Visualização do Corpo de Resposta da Web API

  8. Volte ao Visual Studio e pressione SHIFT + F5 para encerrar a depuração.

Exercício 2: Criação da Interface SPA

Neste exercício, vai primeiro construir a parte front-end web do Geek Quiz, focando-se na interação de aplicação de página única usando AngularJS. Depois, irá melhorar a experiência do utilizador com o CSS3 para realizar animações ricas e proporcionar um efeito visual de mudança de contexto ao transitar de uma pergunta para a seguinte.

Tarefa 1 – Criar a Interface SPA Usando AngularJS

Nesta tarefa vais usar o AngularJS para implementar o lado do cliente da aplicação Geek Quiz. AngularJS é uma framework JavaScript de código aberto que complementa aplicações baseadas em navegador com capacidade Model-View-Controller (MVC), facilitando tanto o desenvolvimento como os testes.

Vai começar por instalar o AngularJS a partir da Console do Gestor de Pacotes do Visual Studio. Depois, irá criar o controlador para fornecer o comportamento da aplicação Geek Quiz e a vista para renderizar as perguntas e respostas do quiz usando o motor de templates AngularJS.

Observação

Para mais informações sobre o AngularJS, consulte [http://angularjs.org/](http://angularjs.org/).

  1. Abra o Visual Studio Express 2013 para Web e abra a solução GeekQuiz.sln localizada na pasta Source/Ex2-CreatingASPAInterface/Begin . Em alternativa, pode continuar com a solução que obteve no exercício anterior.

  2. Abra a Consola do Gestor de Pacotes a partir de Ferramentas>Gestor de Pacotes NuGet. Escreva o seguinte comando para instalar o pacote NuGet AngularJS.Core .

    Install-Package AngularJS.Core
    
  3. No Explorador de Soluções, clique com o botão direito na pasta Scripts do projeto GeekQuiz e selecione Adicionar | Nova Pasta. Nomeie a pasta app e prima Enter.

  4. Clique com o botão direito na pasta da aplicação que acabou de criar e selecione Adicionar | Ficheiro JavaScript.

    Criação de um novo ficheiro JavaScript

    Criação de um novo ficheiro JavaScript

  5. Na caixa de diálogo Especificar Nome para Item , escreva quiz-controller na caixa de texto Nome do Item e clique em OK.

    Nomeação do novo ficheiro JavaScript

    Nomeação do novo ficheiro JavaScript

  6. No ficheiroquiz-controller.js , adicione o seguinte código para declarar e inicializar o controlador AngularJS QuizCtrl .

    (Excerto de Código - 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';
            };
        });
    

    Observação

    A função construtora do controlador QuizCtrl espera um parâmetro injetável chamado $scope. O estado inicial do âmbito deve ser configurado na função construtora anexando propriedades ao objeto $scope . As propriedades contêm o modelo de vista e estarão acessíveis ao template quando o controlador estiver registado.

    O controlador QuizCtrl é definido dentro de um módulo chamado QuizApp. Os módulos são unidades de trabalho que permitem dividir a tua aplicação em componentes separados. As principais vantagens de usar módulos são que o código é mais fácil de compreender e facilita os testes unitários, a reutilização e a manutenção.

  7. Agora irá adicionar comportamento ao âmbito para reagir a eventos desencadeados pela vista. Adicione o código seguinte no final do controlador QuizCtrl para definir a função nextQuestion no objeto $scope .

    (Excerto de Código - 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;
            });
        };
    };
    

    Observação

    Esta função recupera a próxima pergunta da Trivia Web API criada no exercício anterior e anexa os dados da pergunta ao objeto $scope .

  8. Insira o seguinte código no final do controlador QuizCtrl para definir a função sendAnswer no objeto $scope .

    (Excerto de Código - 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;
            });
        };
    };
    

    Observação

    Esta função envia a resposta selecionada pelo utilizador para a API Web do Trivia e armazena o resultado – ou seja, se a resposta está correta ou não – no objeto $scope .

    As funções nextQuestion e sendAnswer indicadas acima usam o objeto $http do AngularJS para abstrair a comunicação com a Web API através do objeto JavaScript XMLHttpRequest do navegador da web. O AngularJS suporta outro serviço que traz um nível superior de abstração para realizar operações CRUD contra um recurso através de APIs RESTful. O objeto $resource AngularJS tem métodos de ação que fornecem comportamentos de alto nível sem necessidade de interagir com o objeto $http . Considere usar o objeto $resource em cenários que requerem o modelo CRUD (para mais informações, veja a documentação $resource).

  9. O passo seguinte é criar o modelo AngularJS que define a vista para o questionário. Para isso, abra o ficheiro Index.cshtml dentro do Views | A pasta Home e substitui o conteúdo pelo seguinte código.

    (Excerto de Código - 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")
    }
    

    Observação

    O template AngularJS é uma especificação declarativa que utiliza informação do modelo e do controlador para transformar a marcação estática na vista dinâmica que o utilizador vê no navegador. Seguem-se exemplos de elementos e atributos de elementos AngularJS que podem ser usados num template:

    • A diretiva ng-app indica ao AngularJS o elemento DOM que representa o elemento raiz da aplicação.
    • A diretiva ng-controller associa um controlador ao DOM no ponto onde a diretiva é declarada.
    • A notação de colchetes curly {{ }} denota ligações às propriedades do âmbito definidas no controlador.
    • A diretiva ng-click é usada para invocar as funções definidas no âmbito em resposta a cliques do utilizador.
  10. Abra o ficheiro Site.css dentro da pasta Conteúdo e adicione os seguintes estilos destacados no final do ficheiro para dar uma visão visual e sensacional para a vista do questionário.

    (Excerto de Código - 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;
    }
    

Tarefa 2 – Executar a Solução

Nesta tarefa, vais executar a solução usando a nova interface de utilizador que criaste com o AngularJS para responder a algumas das perguntas do questionário.

  1. Pressiona F5 para executar a solução.

  2. Regista uma nova conta de utilizador. Para tal, siga os passos de registo descritos no Exercício 1, Tarefa 3.

    Observação

    Se estiver a usar a solução do exercício anterior, pode iniciar sessão com a conta de utilizador que criou anteriormente.

  3. Deverá aparecer a página inicial , mostrando a primeira pergunta do questionário. Responda à pergunta clicando numa das opções. Isto irá ativar a função sendAnswer definida anteriormente, que envia a opção selecionada para a API Web do Trivia .

    Responder a uma pergunta

    Responder a uma pergunta

  4. Depois de clicar num dos botões, a resposta deverá aparecer. Clique em Próxima Pergunta para mostrar a seguinte pergunta. Isto vai ativar a função nextQuestion definida no controlador.

    A solicitar a próxima pergunta

    Solicitar a próxima pergunta

  5. A próxima pergunta deve aparecer. Continua a responder às perguntas quantas vezes quiseres. Depois de completares todas as perguntas, deves voltar à primeira pergunta.

    Outra pergunta

    Próxima pergunta

  6. Volte ao Visual Studio e pressione SHIFT + F5 para encerrar a depuração.

Tarefa 3 – Criar uma Animação de Flip usando CSS3

Nesta tarefa vais usar as propriedades do CSS3 para realizar animações ricas, adicionando um efeito de flip quando uma pergunta é respondida e quando a próxima pergunta for recuperada.

  1. No Explorador de Soluções, clique com o botão direito na pasta Conteúdo do projeto GeekQuiz e selecione Adicionar | Item Existente....

    Adicionar um item existente à pasta Content

    Adicionar um item existente à pasta Content

  2. Na caixa de diálogo Adicionar Item Existente , navegue até à pasta Source/Assets e selecione Flip.css. Clique em Adicionar.

    Adicionar o ficheiro Flip.css de Assets

    Adicionar o ficheiro Flip.css a partir de Assets

  3. Abre o ficheiro Flip.css que acabaste de adicionar e inspeciona o seu conteúdo.

  4. Localiza o comentário sobre a transformação de espelhamento. Os estilos abaixo desse comentário usam as transformações CSS perspetiva e rotateY para gerar um efeito de "virar cartão".

    /* 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. Localiza o comentário ocultar a parte de trás do painel durante a inversão. O estilo abaixo desse comentário esconde o lado de trás das faces quando estão viradas para longe do observador, definindo a propriedade CSS backface-visibility como hidden.

    /* hide back of pane during flip */
    .front, .back {
        -moz-backface-visibility: hidden;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
    }
    
  6. Abra o ficheiro BundleConfig.cs dentro da pasta App_Start e adicione a referência ao ficheiro Flip.css no conjunto de estilo "~/Content/css"

    bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/Content/bootstrap.css",
        "~/Content/site.css",
        "~/Content/Flip.css"));
    
  7. Carrega em F5 para correr a solução e faz login com as tuas credenciais.

  8. Responda a uma pergunta clicando numa das opções. Repara no efeito de inversão ao transitar entre vistas.

    Responder a uma pergunta com o efeito flip

    Responder a uma pergunta com o efeito flip

  9. Clique em Próxima Pergunta para obter a seguinte pergunta. O efeito de inversão deve voltar a aparecer.

    Recuperar a seguinte pergunta com o efeito flip

    A recuperar a pergunta seguinte com o efeito de flip


Resumo

Ao completar este laboratório prático, aprendeu como:

  • Crie um controlador ASP.NET Web API usando ASP.NET Scaffolding
  • Implemente uma API Web Obtenha ação para recuperar a próxima pergunta do questionário
  • Implemente uma ação de Post da Web API para armazenar as respostas do questionário
  • Instale o AngularJS a partir da Consola do Gestor de Pacotes do Visual Studio
  • Implementar templates e controladores AngularJS
  • Use transições CSS3 para realizar efeitos de animação