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:
- Visual Studio Express 2013 para Web o superior
Configuración
Para ejecutar los ejercicios en este laboratorio práctico, primero deberá configurar el entorno.
- Abra el Explorador de Windows y vaya a la carpeta Source del laboratorio.
- 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.
- 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:
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.
Abra Visual Studio Express 2013 para la Web y seleccione Archivo | Nuevo proyecto... para iniciar una nueva solución.
Creación de un proyecto nuevo
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.
Creación de un nuevo proyecto de aplicación web de ASP.NET
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.
Creación de un nuevo proyecto con la plantilla de MVC, incluidos los componentes de la API web
En Explorador de soluciones, haga clic con el botón derecho en la carpetaModelos del proyecto GeekQuiz y seleccione Agregar | Elemento existente....
Agregar un elemento existente
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.
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 .
Abra el archivo Global.asax.cs y agregue la siguiente instrucción.
using GeekQuiz.Models;
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); } }
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.
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>
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>
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>© @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.
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.
Agregue la siguiente instrucción de uso al principio del archivo.
using Newtonsoft.Json.Serialization;
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.
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....
Creación de un nuevo elemento con scaffolding
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.
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.
En el cuadro de diálogo Agregar controlador escriba TriviaController en el cuadro de texto Nombre del controlador y haga clic en Agregar.
Agregar Trivia Controller
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;
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.
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); }
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); }
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; }
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); }
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.
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.
Ejecución de la solución
Haga clic en Registrar para crear un nuevo usuario.
Registro de un nuevo usuario
En la página Registrar, escriba un Nombre de usuario y Contraseña y, a continuación, haga clic en Registrar.
Página de registro
La aplicación registra la nueva cuenta y el usuario se autentica y se redirige de nuevo a la página principal.
El usuario está autenticado
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.
Inicio de la captura de red de API web
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.
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.
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.
Visualización del cuerpo de la respuesta de la API web
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/).
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.
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
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.
Haga clic con el botón derecho en la carpeta aplicación que acaba de crear y seleccione Agregar | Archivo JavaScript.
Creación de un nuevo archivo JavaScript
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.
Asignar un nombre al nuevo archivo JavaScript
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.
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.
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).
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.
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.
Presione F5 para ejecutar la solución.
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.
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.
Responder a una pregunta
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.
Solicitar la siguiente pregunta
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.
Siguiente pregunta
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.
En Explorador de soluciones, haga clic con el botón derecho en la carpeta Contenido del proyecto GeekQuiz y seleccione Agregar | Elemento existente....
Agregar un elemento existente a la carpeta Contenido
En el cuadro de diálogo Agregar elemento existente, vaya a la carpeta origen/recursos y seleccione Flip.css. Haga clic en Agregar.
Agregar el archivo Flip.css desde Assets
Abra el archivo Flip.css que acaba de agregar e inspeccione su contenido.
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); }
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; }
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"));
Presione F5 para ejecutar la solución e iniciar sesión con sus credenciales.
Responda a una pregunta haciendo clic en una de las opciones. Observe el efecto de volteo al realizar la transición entre vistas.
Responder a una pregunta con el efecto de volteo
Haga clic en Siguiente pregunta para acceder a la siguiente pregunta. El efecto de volteo debería aparecer de nuevo.
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