Aplicación de página única: plantilla KnockoutJS

La plantilla de Knockout MVC forma parte de ASP.NET y Web Tools 2012.2

Descargar ASP.NET y Web Tools 2012.2

La actualización ASP.NET y Web Tools 2012.2 incluye una plantilla de aplicación de una sola página (SPA) para ASP.NET MVC 4. Esta plantilla está diseñada para empezar a crear rápidamente aplicaciones web interactivas del lado cliente.

"Aplicación de página única" (SPA) es el término general para una aplicación web que carga una sola página HTML y, a continuación, actualiza la página dinámicamente, en lugar de cargar páginas nuevas. Después de cargar la página inicial, el SPA se comunica con el servidor a través de solicitudes de AJAX.

Diagrama que muestra dos cuadros etiquetados como Cliente y Servidor. Una flecha etiquetada AJAX va del cliente al servidor. Una flecha con la etiqueta H T M L y una flecha con la etiqueta J SON van del servidor al cliente.

AJAX no es nada nuevo, pero en la actualidad hay marcos de JavaScript que facilitan la compilación y el mantenimiento de una aplicación SPA sofisticada de gran tamaño. Además, HTML 5 y CSS3 facilitan la creación de interfaces de usuario enriquecidas.

Para empezar, la plantilla SPA crea una aplicación de ejemplo "Lista de tareas pendientes". En este tutorial, realizaremos un recorrido guiado por la plantilla. En primer lugar, veremos la propia aplicación de lista tareas pendientes y, a continuación, examinaremos las partes de tecnología que hacen que funcione.

Crear un nuevo proyecto de plantilla de SPA

Requisitos:

  • Visual Studio 2012 o Visual Studio Express 2012 para Web
  • ASP.NET actualización de Web Tools 2012.2. Puede instalar la actualización aquí.

Inicie Visual Studio y seleccione Nuevo proyecto en la página Inicio. O bien, en el menú Archivo , seleccione Nuevo y, a continuación, Proyecto.

En el panel Plantillas , seleccione Plantillas instaladas y expanda el nodo Visual C# . En Visual C#, seleccione Web. En la lista de plantillas de proyecto, seleccione ASP.NET aplicación web MVC 4. Asigne un nombre al proyecto y haga clic en Aceptar.

Captura de pantalla que muestra el cuadro de diálogo Nuevo proyecto. Una aplicación web S P dot NET M C C 4 está seleccionada en la lista de plantillas web.

En el Asistente para nuevo proyecto , seleccione Aplicación de página única.

Captura de pantalla que muestra el cuadro de diálogo Nuevo Proyecto de ASP.NET MVC 4. La plantilla Aplicación de página única está seleccionada.

Presione F5 para compilar y ejecutar la aplicación. Cuando se ejecuta la aplicación por primera vez, muestra una pantalla de inicio de sesión.

Captura de pantalla que muestra la pantalla de inicio de sesión de

Haga clic en el vínculo "Registrarse" y cree un nuevo usuario.

Captura de pantalla que muestra la pantalla De registro.

Después de iniciar sesión, la aplicación crea una lista de tareas pendientes predeterminada con dos elementos. Puede hacer clic en "Agregar lista de tareas pendientes" para agregar una nueva lista.

Captura de pantalla que muestra dos listas de tareas pendientes y un botón Agregar lista de tareas pendientes en la parte superior.

Cambie el nombre de la lista, agregue elementos a la lista y márquelos como completados. También puede eliminar elementos o eliminar una lista completa. Los cambios se conservan automáticamente en una base de datos en el servidor (en realidad LocalDB en este momento, porque está ejecutando la aplicación localmente).

Captura de pantalla que muestra una lista con tres elementos. El último elemento está marcado y está tachado.

Arquitectura de la plantilla de SPA

En este diagrama se muestran los bloques de creación principales de la aplicación.

Diagrama que muestra los bloques de construcción independientes del Cliente y el Servidor. Knockout dot j s, H T M L y J SON están bajo el Cliente. A S P punto NET M V C, A S P punto NET Web A P I, Entity Framework y Base de datos están bajo el Servidor.

En el lado servidor, ASP.NET MVC sirve el CÓDIGO HTML y también controla la autenticación basada en formularios.

ASP.NET API web controla todas las solicitudes relacionadas con ToDoLists y ToDoItems, incluida la obtención, creación, actualización y eliminación. El cliente intercambia datos con web API en formato JSON.

Entity Framework (EF) es la capa de O/RM. Media entre el mundo orientado a objetos de ASP.NET y la base de datos subyacente. La base de datos usa LocalDB, pero puede cambiarla en el archivo Web.config. Normalmente, usaría LocalDB para el desarrollo local y, a continuación, implementaría en una base de datos SQL en el servidor mediante la migración de ef code-first.

En el lado cliente, la biblioteca de Knockout.js controla las actualizaciones de página de las solicitudes de AJAX. Knockout usa el enlace de datos para sincronizar la página con los datos más recientes. De este modo, no es necesario escribir ningún código que recorra los datos JSON y actualice el DOM. En su lugar, colocará atributos declarativos en el código HTML que indica a Knockout cómo presentar los datos.

Una gran ventaja de esta arquitectura es que separa la capa de presentación de la lógica de la aplicación. Puede crear la parte de la API web sin saber nada sobre el aspecto de la página web. En el lado cliente, se crea un "modelo de vista" para representar esos datos y el modelo de vista usa Knockout para enlazar con el CÓDIGO HTML. Esto le permite cambiar fácilmente el código HTML sin cambiar el modelo de vista. (Veremos Knockout un poco más tarde).

Models

En el proyecto de Visual Studio, la carpeta Models contiene los modelos que se usan en el lado servidor. (También hay modelos en el lado del cliente; abordaremos esos).

Captura de pantalla que muestra la carpeta Models abierta.

TodoItem, TodoList

Estos son los modelos de base de datos para Entity Framework Code First. Observe que estos modelos tienen propiedades que apuntan entre sí. ToDoList contiene una colección de ToDoItems y cada ToDoItem tiene una referencia a su ToDoList principal. Estas propiedades se denominan propiedades de navegación y representan la relación uno a varios entre una lista de tareas y sus elementos de la lista de tareas.

La ToDoItem clase también usa el atributo [ForeignKey] para especificar que ToDoListId es una clave externa en la ToDoList tabla. Esto indica a EF que agregue una restricción de clave externa a la base de datos.

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

TodoItemDto, TodoListDto

Estas clases definen los datos que se enviarán al cliente. "DTO" significa "objeto de transferencia de datos". El DTO define cómo se serializarán las entidades en JSON. En general, hay varias razones para usar DTO:

  • Para controlar qué propiedades se serializan. El DTO puede contener un subconjunto de las propiedades del modelo de dominio. Puede hacerlo por motivos de seguridad (para ocultar datos confidenciales) o simplemente para reducir la cantidad de datos que envíe.
  • Para cambiar la forma de los datos, por ejemplo, para aplanar una estructura de datos más compleja.
  • Para mantener cualquier lógica empresarial fuera del DTO (separación de preocupaciones).
  • Si los modelos de dominio no se pueden serializar por algún motivo. Por ejemplo, las referencias circulares pueden causar problemas al serializar un objeto Hay maneras de controlar este problema en la API web (consulte Control de referencias de objetos circulares); pero el uso de un DTO simplemente evita el problema por completo.

En la plantilla SPA, los DTO contienen los mismos datos que los modelos de dominio. Sin embargo, siguen siendo útiles porque evitan referencias circulares de las propiedades de navegación y muestran el patrón DTO general.

AccountModels.cs

Este archivo contiene modelos para la pertenencia al sitio. La UserProfile clase define el esquema para los perfiles de usuario en la base de datos de pertenencia. (En este caso, la única información es el identificador de usuario y el nombre de usuario). Las demás clases de modelo de este archivo se usan para crear los formularios de registro y inicio de sesión de usuario.

Entity Framework

La plantilla SPA usa EF Code First. En el desarrollo de Code First, se definen los modelos primero en el código y, a continuación, EF usa el modelo para crear la base de datos. También puede usar EF con una base de datos existente (Database First).

La TodoItemContext clase de la carpeta Models deriva de DbContext. Esta clase proporciona el "pegamento" entre los modelos y Entity Framework (EF). TodoItemContext contiene una ToDoItem colección y una TodoList colección. Para consultar la base de datos, simplemente escriba una consulta LINQ en estas colecciones. Por ejemplo, aquí se muestra cómo puede seleccionar todas las listas de to-do para el usuario "Alice":

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

También puede agregar nuevos elementos a la colección, actualizar elementos o eliminar elementos de la colección y conservar los cambios en la base de datos.

controladores de API web de ASP.NET

En ASP.NET API web, los controladores son objetos que controlan las solicitudes HTTP. Como se mencionó, la plantilla SPA usa la API web para habilitar las operaciones CRUD en ToDoList y ToDoItem. Los controladores se encuentran en la carpeta Controllers de la solución.

Captura de pantalla que muestra la carpeta Controllers abierta.

  • TodoController: controla las solicitudes HTTP para los elementos de tareas pendientes.
  • TodoListController: controla las solicitudes HTTP para las listas de to-do.

Estos nombres son significativos, ya que el Web API compara la ruta URI con el nombre del controlador. (Para obtener información sobre cómo la API web enruta las solicitudes HTTP a los controladores, consulte Enrutamiento en ASP.NET API web).

Echemos un vistazo a la ToDoListController clase . Contiene un miembro de datos único.

private TodoItemContext db = new TodoItemContext();

TodoItemContext se usa para comunicarse con EF, como se describió anteriormente. Los métodos del controlador implementan las operaciones CRUD. La API web asigna solicitudes HTTP del cliente a los métodos de controlador, como se indica a continuación:

Solicitud HTTP Controller (método) Descripción
GET /api/todo GetTodoLists Obtiene una colección de listas de tareas.
GET /api/todo/id GetTodoList Obtiene una lista de tareas pendientes por ID
PUT /api/todo/id PutTodoList Actualiza una lista de tareas.
POST /api/todo PostTodoList Crea una nueva lista de to-do.
DELETE /api/todo/id DeleteTodoList Elimina una lista de tareas pendientes.

Observe que las URI de algunas operaciones contienen marcadores de posición para el valor de ID. Por ejemplo, para eliminar una lista de tareas con un identificador de 42, el URI es /api/todo/42.

Para obtener más información sobre el uso de web API para operaciones CRUD, consulte Creación de una API web que admita operaciones CRUD. El código de este controlador es bastante sencillo. Estos son algunos puntos interesantes:

  • El GetTodoLists método usa una consulta LINQ para filtrar los resultados por el identificador del usuario que ha iniciado sesión. De este modo, un usuario solo ve los datos que le pertenecen. Además, tenga en cuenta que se usa una instrucción Select para convertir las ToDoList instancias en TodoListDto instancias.
  • Los métodos PUT y POST comprueban el estado del modelo antes de modificar la base de datos. Si ModelState.IsValid es false, estos métodos devuelven HTTP 400, Solicitud incorrecta. Obtenga más información sobre la validación de modelos en Web API en Validación de modelos.
  • La clase de controlador también está decorada con el atributo [Authorize]. Este atributo comprueba si la solicitud HTTP está autenticada. Si la solicitud no está autenticada, el cliente recibe HTTP 401, No autorizado. Obtenga más información sobre la autenticación en Autenticación y autorización en ASP.NET API web.

La TodoController clase es muy similar a TodoListController. La mayor diferencia es que no define ningún método GET, ya que el cliente obtendrá las tareas junto con cada lista de tareas.

Controladores y vistas de MVC

Los controladores MVC también se encuentran en la carpeta Controllers de la solución. HomeController representa el HTML principal de la aplicación. La vista del controlador Home se define en Views/Home/Index.cshtml. La vista Inicio representa contenido diferente en función de si el usuario ha iniciado sesión:

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

Cuando los usuarios inician sesión, ven la interfaz de usuario principal. De lo contrario, verán el panel de inicio de sesión. Tenga en cuenta que esta representación condicional se produce en el lado servidor. Nunca intente ocultar contenido confidencial en el lado cliente: todo lo que envíe en una respuesta HTTP es visible para alguien que esté viendo los mensajes HTTP sin procesar.

Client-Side JavaScript y Knockout.js

Ahora vamos a pasar del lado servidor de la aplicación al cliente. La plantilla SPA usa una combinación de jQuery y Knockout.js para crear una interfaz de usuario fluida e interactiva. Knockout.js es una biblioteca de JavaScript que facilita el enlace HTML a los datos. Knockout.js usa un patrón denominado "Model-View-ViewModel".

  • El modelo consiste en los datos del dominio (listas de tareas pendientes y elementos de tareas pendientes).
  • La vista es el documento HTML.
  • El modelo de vista es un objeto de JavaScript que contiene los datos del modelo. El modelo de vista es una abstracción de código de la interfaz de usuario. No tiene conocimiento de la representación HTML. En su lugar, representa características abstractas de la vista, como "una lista de elementos ToDo".

La vista está enlazada al modelo de vista mediante datos. Las actualizaciones del modelo de vista se reflejan automáticamente en la vista. Las vinculaciones también funcionan en la otra dirección. Los eventos del DOM (como los clics) están enlazados a datos a funciones en el modelo de vista, que desencadenan llamadas AJAX.

La plantilla SPA organiza javaScript del lado cliente en tres capas:

  • todo.datacontext.js: envía solicitudes AJAX.
  • todo.model.js: define los modelos.
  • todo.viewmodel.js: define el modelo de vista.

Diagrama que muestra una flecha que va de Knockout dot j s a View Model, luego a Models, y finalmente a Data Context. La flecha entre Knockout dot j s y View Model está etiquetada como enlace de datos y apunta a ambos elementos.

Estos archivos de script se encuentran en la carpeta Scripts o aplicación de la solución.

Captura de pantalla que muestra la subcarpeta etiquetada aplicación abierta.

todo.datacontext controla todas las llamadas AJAX a los controladores de API web. (Las llamadas AJAX para iniciar sesión se definen en otra parte, en ajaxlogin.js).

todo.model.js define los modelos del lado cliente (explorador) para las listas de to-do. Hay dos clases de modelo: todoItem y todoList.

Muchas de las propiedades de las clases de modelo son de tipo "ko.observable". Los observables son cómo Knockout hace su magia. En la documentación de Knockout: un observable es un "objeto javaScript que puede notificar a los suscriptores los cambios". Cuando cambia el valor de un observable, Knockout actualiza todos los elementos HTML enlazados a esos observables. Por ejemplo, todoItem tiene observables para las propiedades título e isDone.

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

También puede suscribirse a un observable en el código. Por ejemplo, la clase todoItem se suscribe a los cambios en las propiedades "isDone" y "title":

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

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

Ver modelo

El modelo de vista se define en todo.viewmodel.js. El modelo de vista es el punto central donde la aplicación enlaza los elementos de página HTML a los datos del dominio. En la plantilla SPA, el modelo de vista contiene una matriz observable de todoLists. El siguiente código en el modelo de vista indica a Knockout que aplique las vinculaciones:

ko.applyBindings(window.todoApp.todoListViewModel);

HTML y enlace de datos

El HTML principal de la página se define en Views/Home/Index.cshtml. Dado que utilizamos la vinculación de datos, el HTML es solo una plantilla para lo que realmente se muestra. Knockout usa enlaces declarativos . Para enlazar elementos de página a datos, agregue un atributo "enlace de datos" al elemento . Este es un ejemplo muy sencillo, tomado de la documentación de Knockout:

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

En este ejemplo, Knockout actualiza el contenido del <elemento span> con el valor de myItems.count(). Cada vez que cambia este valor, Knockout actualiza el documento.

Knockout proporciona una serie de tipos de enlace diferentes. Estos son algunos de los enlaces que se usan en la plantilla spa:

  • foreach: permite recorrer en iteración un bucle y aplicar el mismo marcado a cada elemento de la lista. Se utiliza para renderizar las listas de tareas pendientes y los elementos de tareas pendientes. Dentro de foreach, los enlaces se aplican a los elementos de la lista.
  • visible: se usa para alternar la visibilidad. Oculte el marcado cuando una colección esté vacía o haga que el mensaje de error sea visible.
  • value: se usa para rellenar los valores del formulario.
  • clic: enlaza un evento click a una función en el modelo de vista.

Protección anti-CSRF

La falsificación de solicitud entre sitios (CSRF) es un ataque en el que un sitio malintencionado envía una solicitud a un sitio vulnerable donde el usuario ha iniciado sesión actualmente. Para ayudar a evitar ataques CSRF, ASP.NET MVC usa tokens antifalsificación, también denominados tokens de comprobación de solicitudes. La idea es que el servidor coloca un token generado aleatoriamente en una página web. Cuando el cliente envía datos al servidor, debe incluir este valor en el mensaje de solicitud.

Los tokens antifalsificación funcionan porque la página malintencionada no puede leer los tokens del usuario, debido a directivas de mismo origen. (Las directivas de mismo origen impiden que los documentos hospedados en dos sitios diferentes accedan al contenido del otro).

ASP.NET MVC proporciona compatibilidad integrada con tokens antifalsificación, a través de la clase AntiForgery y el atributo [ValidateAntiForgeryToken]. Actualmente, esta funcionalidad no está integrada en la API web. Sin embargo, la plantilla spa incluye una implementación personalizada para la API web. Este código se define en la ValidateHttpAntiForgeryTokenAttribute clase , que se encuentra en la carpeta Filtros de la solución. Para obtener más información sobre anti-CSRF en la API web, consulte Prevención de ataques de falsificación de solicitudes entre sitios (CSRF).

Conclusión

La plantilla SPA está diseñada para empezar a escribir rápidamente aplicaciones web modernas e interactivas. Usa la biblioteca de Knockout.js para separar la presentación (marcado HTML) de los datos y la lógica de la aplicación. Pero Knockout no es la única biblioteca de JavaScript que puede usar para crear una SPA. Si desea explorar otras opciones, eche un vistazo a las plantillas de SPA creadas por la comunidad.