Laboratorio práctico: Compilar una aplicación de una página (SPA) con ASP.NET Web API y Angular.js

por el equipo de Web Camps

Descarga del kit de entrenamiento de Web Camps

En este laboratorio práctico se muestra cómo crear una aplicación de página única (SPA) con ASP.NET Web API y Angular.js para ASP.NET 4.x.

En este laboratorio práctico, aprovechará esas tecnologías para implementar El cuestionario friki, un sitio web de trivia basado en el concepto SPA. Primero implementará la capa de servicio con ASP.NET Web API para exponer los puntos de conexión necesarios para recuperar las preguntas de prueba y almacenar las respuestas. A continuación, creará una interfaz de usuario enriquecida y con capacidad de respuesta mediante los efectos de transformación AngularJS y CSS3.

En las aplicaciones web tradicionales, el cliente (explorador) inicia la comunicación con el servidor solicitando una página. A continuación, el servidor procesa la petición y envía el HTML de la página al cliente. En interacciones posteriores con la página -por ejemplo, el usuario navega hacia un vínculo o envía un formulario con datos- se envía una nueva solicitud al servidor, y el flujo vuelve a empezar: el servidor procesa la solicitud y envía una nueva página al explorador en respuesta a la nueva acción solicitada por el cliente.

En las aplicaciones de una sola página (SPA), la página completa se carga en el explorador tras la solicitud inicial, pero las interacciones posteriores tienen lugar mediante solicitudes Ajax. Esto significa que el explorador solo tiene que actualizar la parte de la página que ha cambiado; no es necesario recargar toda la página. El enfoque SPA reduce el tiempo que tarda la aplicación en responder a las acciones del usuario, lo que da lugar a una experiencia más fluida.

La arquitectura de una SPA implica ciertos desafíos que no están presentes en las aplicaciones web tradicionales. Sin embargo, las tecnologías emergentes como ASP.NET Web API, marcos de JavaScript como AngularJS y nuevas características de estilo proporcionadas por CSS3 facilitan el diseño y la compilación de SPA.

Todos los fragmentos de código y código de ejemplo se incluyen en el Kit de formación de Web Camps, disponible en https://aka.ms/webcamps-training-kit.

Información general

Objetivos

En este laboratorio práctico, aprenderá a:

  • Crear un servicio de API web de ASP.NET para enviar y recibir datos JSON
  • Crear una interfaz de usuario con capacidad de respuesta mediante AngularJS
  • Mejorar la experiencia de la interfaz de usuario con transformaciones CSS3

Requisitos previos

Se requiere lo siguiente para completar este laboratorio práctico:

Configuración

Para ejecutar los ejercicios en este laboratorio práctico, primero deberá configurar el entorno.

  1. Abra el Explorador de Windows y vaya a la carpeta Source del laboratorio.
  2. Haga clic con el botón derecho en Setup.cmd y seleccione Ejecutar como administrador para iniciar el proceso de instalación que configurará el entorno e instalará los fragmentos de código de Visual Studio para este laboratorio.
  3. Si se muestra el cuadro de diálogo Control de cuentas de usuario, confirme la acción para continuar.

Nota:

Asegúrese de que ha comprobado todas las dependencias de este laboratorio antes de ejecutar la instalación.

Uso de los fragmentos de código

A lo largo del documento de laboratorio, se le pedirá que inserte bloques de código. Para mayor comodidad, la mayoría de este código se proporciona como fragmentos de código de Visual Studio, a los que puede acceder desde Visual Studio 2013 para evitar tener que agregarlo manualmente.

Nota:

Cada ejercicio va acompañado de una solución inicial ubicada en la carpeta Begin del ejercicio que le permite seguir cada ejercicio independientemente de los demás. Tenga en cuenta que los fragmentos de código que se agregan durante un ejercicio faltan en estas soluciones iniciales y es posible que no funcionen hasta que haya completado el ejercicio. Dentro del código fuente de un ejercicio, también encontrará una carpeta End que contiene una solución de Visual Studio con el código que resulta de completar los pasos del ejercicio correspondiente. Puede usar estas soluciones como guía si necesita ayuda adicional a medida que trabaja en este laboratorio práctico.


Ejercicios

Este laboratorio práctico incluye los siguientes ejercicios:

  1. Creación de una API web
  2. Creación de una interfaz SPA

Tiempo estimado para completar este laboratorio: 60 minutos

Nota:

Cuando inicie Visual Studio por primera vez, debe seleccionar una de las colecciones de configuración predefinidas. Cada colección predefinida está diseñada para coincidir con un estilo de desarrollo determinado y determina los diseños de ventana, el comportamiento del editor, los fragmentos de código de IntelliSense y las opciones del cuadro de diálogo. Los procedimientos de este laboratorio describen las acciones necesarias para realizar una tarea determinada en Visual Studio al usar la colección Configuración de desarrollo general. Si elige una colección de configuraciones diferente para el entorno de desarrollo, puede haber diferencias en los pasos que debe tener en cuenta.

Ejercicio 1: Creación de una API web

Una de las partes clave de una SPA es la capa de servicio. Se encarga de procesar las llamadas Ajax enviadas por la interfaz de usuario y de devolver datos en respuesta a esa llamada. Los datos recuperados deben presentarse en un formato legible por la máquina para que el cliente pueda analizarlos y consumirlos.

El marco API de web forma parte de la ASP.NET Stack y está diseñado para facilitar la implementación de servicios HTTP, por lo general enviando y recibiendo datos con formato JSON o XML a través de una API RESTful. En este ejercicio crearás el sitio Web para hospedar la aplicación Geek Quiz y luego implementarás el servicio back-end para exponer y persistir los datos del cuestionario usando la ASP.NET Web API.

Tarea 1: Crear el proyecto inicial para Geek Quiz

En esta tarea, comenzará a crear un nuevo proyecto de ASP.NET MVC compatible con ASP.NET Web API basado en el tipo de proyecto One ASP.NET que se incluye con Visual Studio. One ASP.NET unifica todas las tecnologías de ASP.NET y le ofrece la opción de mezclarlas y combinarlas según sea necesario. A continuación, agregará las clases de modelo de Entity Framework y el inicializador de base de datos para insertar las preguntas de la prueba.

  1. Abra Visual Studio Express 2013 para la Web y seleccione Archivo | Nuevo proyecto... para iniciar una nueva solución.

    Creating a New Project

    Creación de un proyecto nuevo

  2. En el cuadro de diálogo nuevo proyecto, seleccione Aplicación web ASP.NET en la pestaña Visual C# | Web. Asegúrese de que NET Framework 4.5 está seleccionado, nómbrelo GeekQuiz, elija una Ubicación y haga clic en Aceptar.

    Creating a new ASP.NET Web Application project

    Creación de un nuevo proyecto de aplicación web de ASP.NET

  3. En el cuadro de diálogo Nuevo proyecto de ASP.NET, seleccione la plantilla MVCy seleccione la opción Web API. Además, asegúrese de que la opción Autenticación esté establecida en cuentas de usuario individuales. Haga clic en Aceptar para continuar.

    Creating a new project with the MVC template, including Web API components

    Creación de un nuevo proyecto con la plantilla de MVC, incluidos los componentes de la API web

  4. En Explorador de soluciones, haga clic con el botón derecho en la carpetaModelos del proyecto GeekQuiz y seleccione Agregar | Elemento existente....

    Adding an existing item

    Agregar un elemento existente

  5. En el cuadro de diálogo Agregar elemento existente, vaya a la carpeta source/Assets/Models y seleccione todos los archivos. Haga clic en Agregar.

    Adding the model assets

    Agregar los recursos del modelo

    Nota:

    Al agregar estos archivos, va a agregar el modelo de datos, el contexto de la base de datos de Entity Framework y el inicializador de la base de datos para la aplicación Geek Quiz.

    Entity Framework (EF) es un asignador relacional de objetos (ORM) que permite crear aplicaciones de acceso a datos mediante la programación con un modelo de aplicación conceptual en lugar de programar directamente mediante un esquema de almacenamiento relacional. Puede obtener más información sobre Entity Framework aquí.

    A continuación se muestra una descripción de las clases que acaba de agregar:

    • TriviaOption: representa una sola opción asociada a una pregunta de cuestionario
    • TriviaQuestion: representa una pregunta de prueba y expone las opciones asociadas a través de la propiedad Opciones
    • TriviaAnswer: representa la opción seleccionada por el usuario en respuesta a una pregunta de prueba
    • TriviaContext: representa el contexto de base de datos de Entity Framework de la aplicación Geek Quiz. Esta clase deriva de DContext y expone las propiedades DbSet que representan colecciones de las entidades descritas anteriormente.
    • TriviaDatabaseInitializer: la implementación del inicializador de Entity Framework para la clase TriviaContext que hereda de CreateDatabaseIfNotExists. El comportamiento predeterminado de esta clase es crear la base de datos solo si no existe, insertando las entidades especificadas en el método de Inicialización .
  6. Abra el archivo Global.asax.cs y agregue la siguiente instrucción.

    using GeekQuiz.Models;
    
  7. Agregue el código siguiente al principio del método Application_Start para establecer el TriviaDatabaseInitializer como inicializador de base de datos.

    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. Modifique el controlador de inicio para restringir el acceso a los usuarios autenticados. Para ello, abra el archivo HomeController.cs dentro de la carpeta Controllers y agregue el atributo Autorizar a la definición de clase HomeController.

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

    Nota:

    El filtroAutorizar comprueba si el usuario está autenticado. Si el usuario no está autenticado, devuelve el código de estado HTTP 401 (no autorizado) sin invocar la acción. Puede aplicar el filtro globalmente, en el nivel de controlador o en el nivel de acciones individuales.

  9. Ahora personalizará el diseño de las páginas web y la personalización de marca. Para ello, abra el archivo _Layout.cshtml dentro de Vistas | Carpeta compartida y actualice el contenido del <título>elemento reemplazando My ASP.NET Application con 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. En el mismo archivo, actualice la barra de navegación quitando los vínculos Acerca de y Contacto y cambiando el nombre del vínculoInicio a Reproducir. Además, cambie el nombre del vínculo Nombre de la aplicación a Geek Quiz . El código HTML de la barra de navegación debe ser similar al código siguiente.

    <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. Actualice el pie de página del diseño reemplazando My ASP.NET Application por Geek Quiz. Para ello, reemplace el contenido del elemento<pie de página> por el código resaltado siguiente.

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

Tarea 2: Creación de la API web TriviaController

En la tarea anterior, creó la estructura inicial de la aplicación web Geek Quiz. Ahora creará un servicio de API web simple que interactúa con el modelo de datos de la prueba y expone las siguientes acciones:

  • GET /api/trivia: recupera la siguiente pregunta de la lista de cuestionarios que el usuario autenticado va a responder.
  • POST /api/trivia: almacena la respuesta del cuestionario especificada por el usuario autenticado.

Usará las herramientas de andamiaje de ASP.NET proporcionadas por Visual Studio para crear la línea base para la clase de controlador de API web.

  1. Abra el archivo WebApiConfig.cs dentro de la carpeta App_Start. Este archivo define la configuración del servicio api web, como cómo se asignan las rutas a las acciones del controlador de API web.

  2. Agregue la siguiente instrucción de uso al principio del archivo.

    using Newtonsoft.Json.Serialization;
    
  3. Agregue el código resaltado siguiente al método Register para configurar globalmente el formateador para los datos JSON recuperados por los métodos de acción de API web.

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

    Nota:

    El CamelCasePropertyNamesContractResolver convierte automáticamente los nombres de propiedad en notación camello, que es la convención general para los nombres de propiedad en JavaScript.

  4. En Explorador de soluciones, haga clic con el botón derecho en la carpeta Controllers del proyecto GeekQuiz y seleccione Agregar | Nuevo elemento con scaffolding....

    Creating a new scaffolded item

    Creación de un nuevo elemento con scaffolding

  5. En el cuadro de diálogo Agregar scaffolding, asegúrese de que el nodo común está seleccionado en el panel izquierdo. A continuación, seleccione la plantilla Controladora de API web 2- Vacía en el panel central y haga clic en Agregar.

    Selecting the Web API 2 Controller Empty template

    Selección de la plantilla Vacía del controlador de Web API 2

    Nota:

    ASP.NET Scaffolding es un marco de generación de código para aplicaciones web de ASP.NET. Visual Studio 2013 incluye generadores de código preinstalados para proyectos de MVC y API web. Debe usar scaffolding en el proyecto cuando desee agregar rápidamente código que interactúe con los modelos de datos para reducir la cantidad de tiempo necesario para desarrollar operaciones de datos estándar.

    El proceso de scaffolding también garantiza que todas las dependencias necesarias estén instaladas en el proyecto. Por ejemplo, si empieza con un proyecto de ASP.NET vacío y, a continuación, usa scaffolding para agregar un controlador de API web, los paquetes NuGet de API web necesarios y las referencias se agregan automáticamente al proyecto.

  6. En el cuadro de diálogo Agregar controlador escriba TriviaController en el cuadro de texto Nombre del controlador y haga clic en Agregar.

    Adding the Trivia Controller

    Agregar Trivia Controller

  7. A continuación, el archivo TriviaController.cs se agrega a la carpeta Controllers del proyecto GeekQuiz, que contiene una clase TriviaControllervacía. Agregue las siguientes instrucciones de uso al principio del archivo.

    (Fragmento 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. Agregue el código siguiente al principio de la clase TriviaController para definir, inicializar y eliminar la instancia de TriviaContext en el controlador.

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

    Nota:

    El método Dispose de TriviaController invoca el método Dispose de la instancia de TriviaContext, lo que garantiza que todos los recursos utilizados por el objeto de contexto se libere cuando la instancia de TriviaContext se elimine o recopile elementos no utilizados. Esto incluye cerrar todas las conexiones de base de datos abiertas por Entity Framework.

  9. Agregue el siguiente método auxiliar al final de la clase TriviaController. Este método recupera la siguiente pregunta de cuestionario de la base de datos a la que responde el usuario especificado.

    (Fragmento 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. Agregue el siguiente método de acciónGet a la clase TriviaController. Este método de acción llama al método auxiliar NextQuestionAsync definido en el paso anterior para recuperar la siguiente pregunta para el usuario autenticado.

    (Fragmento 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. Agregue el siguiente método auxiliar al final de la clase TriviaController. Este método almacena la respuesta especificada en la base de datos y devuelve un valor booleano que indica si la respuesta es correcta o no.

    (Fragmento 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. Agregue el siguiente método de acción Post a la clase TriviaController. Este método de acción asocia la respuesta al usuario autenticado y llama al método auxiliar de StoreAsync. A continuación, envía una respuesta con el valor booleano devuelto por el método auxiliar.

    (Fragmento 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. Modifique el controlador de API web para restringir el acceso a los usuarios autenticados mediante la adición del atributo Authorize a la definición de clase TriviaController.

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

Tarea 3: Ejecución de la solución

En esta tarea, comprobará que el servicio de API web que creó en la tarea anterior funciona según lo previsto. Usará las Herramientas de desarrollo F12 de Internet Explorer para capturar el tráfico de red e inspeccionará la respuesta completa del servicio de API web.

Nota:

Asegúrese de que Internet Explorer está seleccionado en el botón Iniciar situado en la barra de herramientas de Visual Studio.

Internet Explorer option

  1. Presione F5 para ejecutar la solución. La página Iniciar sesión debería aparecer en el explorador.

    Nota:

    Cuando se inicia la aplicación, se desencadena la ruta MVC predeterminada, que de forma predeterminada se asigna a la acción Index de la clase HomeController. Dado que HomeController está restringido a los usuarios autenticados (recuerde que ha decorado esa clase con el atributo Authorize en el ejercicio 1) y aún no hay ningún usuario autenticado, la aplicación redirige la solicitud original a la página de inicio de sesión.

    Running the solution

    Ejecución de la solución

  2. Haga clic en Registrar para crear un nuevo usuario.

    Registering a new user

    Registro de un nuevo usuario

  3. En la página Registrar, escriba un Nombre de usuario y Contraseña y, a continuación, haga clic en Registrar.

    Register page

    Página de registro

  4. La aplicación registra la nueva cuenta y el usuario se autentica y se redirige de nuevo a la página principal.

    User is authenticated

    El usuario está autenticado

  5. En el explorador, pulse F12 para abrir el panel Herramientas del desarrollador. Presione CTRL + 4 o haga clic en el iconoRed y, a continuación, haga clic en el botón de flecha verde para empezar a capturar el tráfico de red.

    Initiating Web API network capture

    Inicio de la captura de red de API web

  6. Anexe api/trivia a la dirección URL de la barra de direcciones del explorador. Ahora inspeccionará los detalles de la respuesta del método de acción Get en TriviaController.

    Retrieving the next question data through Web API

    Recuperación de los datos de la siguiente pregunta a través de la API web

    Nota:

    Una vez finalizada la descarga, se le pedirá que realice una acción con el archivo descargado. Deje abierto el cuadro de diálogo para poder ver el contenido de la respuesta a través de la ventana Herramientas de desarrolladores.

  7. Ahora inspeccionará el cuerpo de la respuesta. Para ello, haga clic en la pestaña Detalles y después en Cuerpo de la respuesta. Puede comprobar que los datos descargados son un objeto con las propiedades opciones (que es una lista de objetos TriviaOption), id y título que corresponden a la clase TriviaQuestion.

    Viewing the Web API Response Body

    Visualización del cuerpo de la respuesta de la API web

  8. Vuelva a Visual Studio y presione MAYÚS + F5 para detener la depuración.

Ejercicio 2: Creación de la interfaz SPA

En este ejercicio, primero creará la parte de front-end web de Geek Quiz, centrándose en la interacción de la aplicación de página única mediante AngularJS. A continuación, mejorará la experiencia del usuario con CSS3 para realizar animaciones enriquecidas y proporcionará un efecto visual del cambio de contexto al pasar de una pregunta a la siguiente.

Tarea 1: Creación de la interfaz SPA mediante AngularJS

En esta tarea usará AngularJS para implementar el lado cliente de la aplicación Geek Quiz. AngularJS es un marco de JavaScript de código abierto que aumenta las aplicaciones basadas en explorador con la funcionalidad Model-View-Controller (MVC), lo que facilita el desarrollo y las pruebas.

Empezará instalando AngularJS desde la consola del Administrador de paquetes de Visual Studio. A continuación, creará el controlador para proporcionar el comportamiento de la aplicación Geek Quiz y la vista para representar las preguntas y respuestas de la prueba mediante el motor de plantillas de AngularJS.

Nota:

Para obtener más información sobre AngularJS, consulte [http://angularjs.org/](http://angularjs.org/).

  1. Abra Visual Studio Express 2013 para Web y abra la solución de GeekQuiz.sln ubicada en la carpeta Source/Ex2-CreatingASPAInterface/Begin. Como alternativa, puede continuar con la solución que obtuvo en el ejercicio anterior.

  2. Abra la consola del Administrador de paquetes desde Herramientas>Administrador de paquetesNuGet. Escriba el siguiente comando para instalar el paquete NuGetAngularJS.Core.

    Install-Package AngularJS.Core
    
  3. En Explorador de soluciones, haga clic con el botón derecho en la carpeta scripts del proyecto GeekQuiz y seleccione Agregar | Nueva carpeta. Asigne un nombre a la carpeta de la aplicación y presione Entrar.

  4. Haga clic con el botón derecho en la carpeta aplicación que acaba de crear y seleccione Agregar | Archivo JavaScript.

    Creating a new JavaScript file

    Creación de un nuevo archivo JavaScript

  5. En el cuadro de diálogo Especificar nombre para elemento cuadro de diálogo, escriba quiz-controller en el cuadro de texto nombre de elemento y haga clic en Aceptar.

    Naming the new JavaScript file

    Asignar un nombre al nuevo archivo JavaScript

  6. En el archivo quiz-controller.js, agregue el código siguiente para declarar e inicializar el controlador QuizCtrl de AngularJS.

    (Fragmento 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';
            };
        });
    

    Nota:

    La función constructora del controlador QuizCtrl espera un parámetro insertable denominado $scope. El estado inicial del ámbito debe configurarse en la función constructor adjuntando propiedades al objeto $scope. Las propiedades contienen el modelo de vista y serán accesibles para la plantilla cuando se registre el controlador.

    El controlador QuizCtrl se define dentro de un módulo denominado QuizApp. Los módulos son unidades de trabajo que permiten dividir la aplicación en componentes independientes. Las principales ventajas de usar módulos es que el código es más fácil de entender y facilita las pruebas unitarias, la reutilización y el mantenimiento.

  7. Ahora agregará el comportamiento al ámbito para reaccionar a los eventos desencadenados desde la vista. Agregue el código siguiente al final del controlador QuizCtrl para definir la función nextQuestion en el objeto $scope.

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

    Nota:

    Esta función recupera la siguiente pregunta de la API web de Trivia creada en el ejercicio anterior y adjunta los datos de la pregunta al objeto $scope.

  8. Inserte el código siguiente al final del controladorQuizCtrl para definir la función sendAnswer en el objeto $scope.

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

    Nota:

    Esta función envía la respuesta seleccionada por el usuario al API webTrivia y almacena el resultado, es decir, si la respuesta es correcta o no, en el objeto $scope.

    Las funciones nextQuestion y sendAnswer anteriores usan el objeto de AngularJS $http para abstraer la comunicación con la API web a través del objeto JavaScript XMLHttpRequest desde el explorador. AngularJS admite otro servicio que aporta un mayor nivel de abstracción para realizar operaciones CRUD en un recurso a través de las API de RESTful. El objeto AngularJS $resource tiene métodos de acción que proporcionan comportamientos de alto nivel sin necesidad de interactuar con el objeto $http . Considere la posibilidad de usar el objeto $resource en escenarios que requieren el modelo CRUD (para obtener información, consulte la documentación de $resource).

  9. El siguiente paso consiste en crear la plantilla de AngularJS que define la vista del cuestionario. Para ello, abra el archivo Index.cshtml dentro de las carpeta Vistas| Inicio y reemplace el contenido por el código siguiente.

    (Fragmento 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")
    }
    

    Nota:

    La plantilla de AngularJS es una especificación declarativa que usa información del modelo y el controlador para transformar el marcado estático en la vista dinámica que el usuario ve en el explorador. A continuación se muestran ejemplos de elementos y atributos de elemento de AngularJS que se pueden usar en una plantilla:

    • La directiva ng-app indica a AngularJS el elemento DOM que representa el elemento raíz de la aplicación.
    • La directiva ng-controller adjunta un controlador al DOM en el momento en que se declara la directiva.
    • La notación de llave {{ }} denota enlaces a las propiedades de ámbito definidas en el controlador.
    • La directiva ng-click se usa para invocar las funciones definidas en el ámbito en respuesta a los clics del usuario.
  10. Abra el archivo Site.css dentro de la carpeta Contenido y agregue los siguientes estilos resaltados al final del archivo para proporcionar una apariencia y sensación para la vista de cuestionario.

    (Fragmento 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;
    }
    

Tarea 2: Ejecución de la solución

En esta tarea, ejecutará la solución mediante la nueva interfaz de usuario que creó con AngularJS para responder a algunas de las preguntas de la prueba.

  1. Presione F5 para ejecutar la solución.

  2. Registre una nueva cuenta de usuario. Para ello, siga los pasos de registro descritos en ejercicio 1, tarea 3.

    Nota:

    Si usa la solución del ejercicio anterior, puede iniciar sesión con la cuenta de usuario que creó antes.

  3. Debería aparecer la página Inicio, en la que se muestra la primera pregunta del cuestionario. Responda a la pregunta haciendo clic en una de las opciones. Esto desencadenará la función sendAnswer definida anteriormente, que envía la opción seleccionada a la API web de Trivia.

    Answering a question

    Responder a una pregunta

  4. Después de hacer clic en uno de los botones, debería aparecer la respuesta. Haga clic en Siguiente pregunta para mostrar la siguiente pregunta. Esto desencadenará la función nextQuestion definida en el controlador.

    Requesting the next question

    Solicitar la siguiente pregunta

  5. La siguiente pregunta debería aparecer. Siga respondiendo preguntas tantas veces como desee. Después de completar todas las preguntas, debe volver a la primera pregunta.

    Another question

    Siguiente pregunta

  6. Vuelva a Visual Studio y presione MAYÚS + F5 para detener la depuración.

Tarea 3: Crear una Animación de volteo con CSS3

En esta tarea, usará las propiedades CSS3 para realizar animaciones enriquecidas agregando un efecto de volteo cuando se responda a una pregunta y cuando se recupere la siguiente pregunta.

  1. En Explorador de soluciones, haga clic con el botón derecho en la carpeta Contenido del proyecto GeekQuiz y seleccione Agregar | Elemento existente....

    Adding an existing item to the Content folder

    Agregar un elemento existente a la carpeta Contenido

  2. En el cuadro de diálogo Agregar elemento existente, vaya a la carpeta origen/recursos y seleccione Flip.css. Haga clic en Agregar.

    Adding the Flip.css file from Assets

    Agregar el archivo Flip.css desde Assets

  3. Abra el archivo Flip.css que acaba de agregar e inspeccione su contenido.

  4. Busque el comentario de transformación de volteo. Los estilos siguientes que comentan usan las transformaciones de CSS de perspectiva y rotateY para generar un efecto de "volteo de tarjeta".

    /* 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. Busque el comentarioocultar la parte posterior del panel durante el volteo. El estilo debajo de ese comentario oculta el lado posterior de las caras cuando se alejan del visor estableciendo la propiedad CSS visibilidad inversa en oculta.

    /* hide back of pane during flip */
    .front, .back {
        -moz-backface-visibility: hidden;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
    }
    
  6. Abra el archivo BundleConfig.cs dentro de la carpeta App_Start y agregue la referencia al archivo Flip.css en el paquete de estilos"~/Content/css"

    bundles.Add(new StyleBundle("~/Content/css").Include(
        "~/Content/bootstrap.css",
        "~/Content/site.css",
        "~/Content/Flip.css"));
    
  7. Presione F5 para ejecutar la solución e iniciar sesión con sus credenciales.

  8. Responda a una pregunta haciendo clic en una de las opciones. Observe el efecto de volteo al realizar la transición entre vistas.

    Answering a question with the flip effect

    Responder a una pregunta con el efecto de volteo

  9. Haga clic en Siguiente pregunta para acceder a la siguiente pregunta. El efecto de volteo debería aparecer de nuevo.

    Retrieving the following question with the flip effect

    Acceder a la siguiente pregunta con el efecto de volteo


Resumen

Al finalizar este laboratorio práctico habrá aprendido a:

  • Crear un controlador de API web de ASP.NET mediante scaffolding de ASP.NET
  • Implementar una acción de obtención de API web para acceder a la siguiente pregunta del cuestionario
  • Implementar una acción de publicar API web para almacenar las respuestas de la prueba
  • Instalar AngularJS desde la consola del Administrador de paquetes de Visual Studio
  • Implementar plantillas y controladores de AngularJS
  • Usar transiciones CSS3 para realizar efectos de animación