Esta es la versión ACTUALIZADA y REVISADA de mi artículo anterior: Construyendo aplicaciones elegantes con ASP.NET MVC Core 2 y Bootstrap 4 usando CoreUI

En este artículo explicaré cómo adaptar la recién lanzada versión (v2.0.0) del template CoreUI, basado en Bootstrap 4, para usarlo como base para aplicaciones ASP.NET MVC Core 2.1.

En realidad, “adaptar” es más que nada ejecutar mi primer programa en JS, presentado como un PR al repositorio de CoreUI.

Aunque este es un artículo específico de ASP.NET Core MVC 2.1, la idea general debería, al menos, servir como guía para otros frameworks fuera del mundo .NET.

Puntos Importante
  1. Conceptos clave sobre el manejo de paquetes del lado del cliente con npm

  2. Comprender las relaciones entre las vistas principales, las vistas de layout y las vistas parciales.

  3. Manejo de layouts anidados

  4. Personalización de vistas de Identidad 2.1 desde paquetes de UI

Programas fuente

Artículo: AspNetCore2CoreUI-2.0.zip (release 2.0 del repositorio)
Repositorio: https://github.com/mvelosop/AspNetCore2CoreUI

Contexto

Ha pasado un tiempo desde que escribí el primer artículo en CoreUI y en estas fechas (MAY-2018), hay nuevas versiones/candidatos tanto para ASP.NET MVC Core (v2.1) como para CoreUI (v2.0.0) y, además, he llegado a conocer un poco más sobre temas de front-end, así que pensé que sería un buen momento para publicar un artículo actualizado y revisado.

El proceso de adaptación de CoreUI va a ser un poco diferente al del artículo anterior, para empezar, ahora todo está centrado en npm, ya que bower y gulp han sido eliminados tanto de VS como de CoreUI y CoreUI está utilizando las capacidades de ejecución de tareas de npm.

Por otro lado, el proceso será mucho más rápido gracias a un programa de NODE que desarrollé y envié como PR a CoreUI. También espero que el proceso sea mucho más claro.

Desde MAY-2018, ASP.NET Core 2.1 sólo es compatible con Visual Studio 2017 15.7 o posterior..

No espero que este artículo se vea demasiado afectado por el lanzamiento final de todos los productos involucrados, pero lo actualizaré en caso de que sea necesario.

Platforma y Herramientas

El proceso de adaptación se simplifica mucho utilizando una herramienta de comparación de archivos. Recomiendo Beyond Compare, que he estado usando desde 1998, pero hay otras herramientas similares que deberían funcionar igual de bien.

Paso a paso

1 - Crear un proyecto ASP.NET MVC Core 2.1

Comencemos por crear una aplicación MVC estándar, usando la plantilla integrada de Visual Studio 2017.

1.1 - Crear una solución en blanco

  1. Crear una “solución en blanco” llamada AspNetCore21CoreUI2 con un repositorio Git

  2. Añada un archivo .editorconfig a la solución para estandarizar algunas opciones de formato para el proyecto. (después de instalar el EditorConfig Language Services)

  3. Agregar un solution folder src

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/2018-04-25_19-27-17.png
.editorconfig
[AspNetCore2CoreUI-2.0]
1
2
3
4
5
6
7
8
root = true

[*]
indent_size = 4
indent_style = space

[*.cshtml]
indent_size = 2

Ahora mismo su solución debería verse como esto:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-04-25_19-43-26.png

1.2 - Añadir un proyecto ASP.NET MVC Core 2.1

  1. Cree el proyecto CoreUI.Mvc de tipo ASP.NET Core Web Application en la carpeta src de la solución:

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-04-08_14-25-47.png
    y al buscar la carpeta, cree la carpeta src en el sistema de archivos:
    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/2018-04-08_14-31-44.png

  2. Seleccione una aplicación de tipo ASP.NET Core 2.1 MVC y

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-04-08_14-37-27.png

  3. Cambiar la autenticación a Individual User Accounts y Store user accounts in-app.

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-04-08_14-40-18.png

Ahora mismo su solución debería verse así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-04-25_19-48-08.png

1.3 - Crear la base de datos

  1. Cambie el string de conexión en el archivo appsettings.json para usar un nombre más “bonito” para la base de datos.

    1
    
    Server=(localdb)\\mssqllocaldb; Database=CoreUI.Mvc; Trusted_Connection=True; MultipleActiveResultSets=true

  2. Ejecute la aplicación usando [Ctrl]+[F5]

  3. Regístrese para forzar la creación de la base de datos

  4. Haga click en Apply Migrations, cuando se presente el error por falta de la base de datos:

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-04-08_14-56-23.png

  5. Refresque la pantalla (re-posteando el registro) cuando termine el proceso de creación de la base de datos, para completar el registro del usuario

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-04-08_14-58-08.png

Este es un buen momento para guardar el proyecto en el repositorio!

1.4 - Eliminar bibliotecas originales del lado del cliente

La carpeta wwwroot es la raíz del lado cliente de la aplicación, por lo que todos los archivos estáticos deben estar dentro de este árbol de carpetas.

Ahora vamos a eliminar todas las librerías del lado del cliente incluidas por la plantilla de Visual Studio, porque vamos a usar las de CoreUI.

  1. Abra la carpeta wwwroot y anote las librerías utilizadas:

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-04-08_15-13-44.png
    La carpeta bootstrap contiene todo el “look and feel” general de la aplicación, pero esto es lo que va a ser reemplazado por CoreUI, así que vamos a ignorar completamente esta carpeta.

    CoreUI está basado en Bootstrap, pero crea un style.css adaptado, compilando los archivos .scss de Bootstrap.

    Las librerías jquery* se utilizan para la interactividad y validación del lado del cliente, por lo que más adelante las añadiremos a la aplicación MVC CoreUI, pero sólo tomaremos nota de las librerías utilizadas, podemos comprobar las versiones en el archivo .bower.json en cada carpeta, en este caso:

    • jquery (3.3.1)
    • jquery-validation (1.17.0)
    • jquery-validation-unobtrusive (3.2.9)
  2. Elimine la carpeta wwwroot\lib.
    (Si no la puede eliminar, podría ser necesario cerrar VS y hacerlo desde el explorador de archivos.)

  3. Ejecute la aplicación con [Ctrl]+[F5] para mostrarla sin ningún estilo (o Javascript)

    Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-04-08_15-40-50.png

Guardemos esta versión en el repositorio ahora

2 - Prepare el sitio de despliegue de CoreUI

Ahora vamos a preparar el sitio de despliegue (distribución) a partir de la última versión de CoreUI, que luego copiaremos a nuestra aplicación ASP.NET Core MVC.

2.1 - Prepare su repositorio base CoreUI

En este momento tiene dos opciones:

  1. Clonar el repositorio maestro de CoreUI en GitHub para aprender el proceso en detalle o

  2. Clonar mi fork, específico para ASP.NET Core MVC 2.1, del repositorio de CoreUI en GitHub para obtener resultados más rápidamente.

Mi fork agrega un conjunto de programas Node (Javascript) para generar vistas básicas de Razor a partir de los archivos html estáticos de CoreUI, con sólo un comando.

Ya he enviado un PR para incluir esto en el repositorio maestro de CoreUI pero, mientras tanto, Supongo que prefirirá la ruta rápida, así que explicaré los pasos suponiendo que está clonando mi fork de CoreUI.

De todos modos en esta sección (#2) debería obtener casi los mismos resultados de ambos repositorios, la sección #3 es donde se mostrarán las grandes diferencias.

Entonces, comencemos por clonar mi fork, desde la línea de comandos ejecute:

1
git clone https://github.com/mvelosop/coreui-free-bootstrap-admin-template mvelosop-coreui-free-bootstrap-admin-template

En mi fork, la rama por defecto es aspnetcore (específica para ASP.NET Core MVC), mientras que la rama por defecto en el repositorio maestro es master.

Ahora vamos a crear una nueva rama para hacer nuestras personalizaciones, entonces vamos a llamarla dist:

1
2
cd ./mvelosop-coreui-free-bootstrap-admin-template
git checkout -b dist aspnetcore

2.2 - Crear la carpeta de distribución (archivos estáticos estándar)

Primero necesitamos instalar las dependencias del lado del cliente, así que, desde la carpeta coreui-freebootstrap-admin-template, ejecute este comando:

1
npm install

Esto crea la carpeta node_modules con todas las dependencias, tal y como se ha configurado en la colección dependencias en el archivo package.json.

Mi fork agrega algunos scripts a package.json, y algunos paquetes adicionales:

  • build-aspnetcore : Este es el que hace la magia, y
  • test * Esta es la que se asegura de que la magia esté bien ;-)

Ejecute este comando para verificar que el sitio funciona correctamente:

1
npm run serve

Eso debería abrir su navegador por defecto en http://localhost:3000/ donde debería ver algo como esto:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-04-08_19-54-45.png

Para generar finalmente la carpeta de distribución basta con ejecutar el comando (tras interrumpir el servidor de node con [Ctrl]+[C]):

1
npm run build

Esto crea la carpeta dist (.gitignore’d) dentro de la carpeta repo con algo como esto:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/explorer_2018-04-09_13-47-00.png

Este es el sitio de despliegue estático base, listo para ser publicado, y con sólo hacer doble clic en cualquier archivo html (excepto 404, 500, login o register) puede explorar la plantilla CoreUI base.

Hasta este punto, obtendrá el mismo resultado con el repo maestro o con mi fork.

2.3 - Crear la carpeta de distribución para ASP.NET Core MVC

Similar a lo que acabamos de hacer, para crear la carpeta de distribución para ASP.NET Core MVC, cuando se clona mi fork, sólo es necesario ejecutar:

1
npm run build-aspnetcore

Este comando borra la carpeta dist anterior y genera algo como esto, siguiendo las convenciones de ASP.NET:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/explorer_2018-04-26_15-37-04.png

Donde podemos destacar lo siguiente:

  1. Las imágenes están ahora en la carpeta images en lugar de img.

  2. Los archivos de los paquetes requeridos están en la carpeta lib en lugar de vendors.

  3. La carpeta lib está ahora organizada de la misma manera que node_modules (pero incluyendo sólo los archivos realmente referenciados, más cualquier archivo .map existente y requerido)

  4. Una vista Razor (.cshtml) por cada archivo html estático de CoreUI.

Al igual que antes, podemos hacer doble clic en cualquier archivo html (excepto 404, 500, login o register) para explorar la plantilla CoreUI base, con la estructura de carpetas ASP.NET Core MVC.

Si abrimos un par de archivos .html/.cshtml con Beyond Compare, o un comparador de archivos similar, podemos comprobar las diferencias para entender los cambios que hace el script build-aspnetcore:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/BCompare_2018-04-26_15-53-10.png
Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/BCompare_2018-04-26_15-55-23.png
  1. Borrar el layout por defecto porque (en este momento) la página tiene todo lo que necesita

  2. Escapar el caracter @ (un símbolo reservado de Razor)

  3. Añadir el prefijo de ruta “home” ~/ para los archivos css y js

  4. Añadir el prefijo de ruta “home” ~/ para las imágenes y todos los demás archivos estáticos

  5. Cambiar los enlaces a los archivos html, para apuntar a las acciones del controlador ASP.NET usando tag helpers de Razor

Si no estuviese usando el script build-aspnetcore de mi fork, tendría que hacer esos cambios a mano en todos y cada uno de los archivos html.

2.4 - Instalar las dependencias del lado del cliente para las vistas ASP.NET MVC

Ahora instalaremos las dependencias identificadas en 1.4.

Para instalar las dependencias sólo tenemos que añadir estas líneas a la colección dependencies de packages.json, haciendo referencia a las últimas versiones de los paquetes:

1
2
3
"jquery":"3.3.1",
"jquery-validation":"1.17.0",
"jquery-validation-unobtrusive":"3.2.9",

Así que el archivo debería resultar en algo como esto:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/Code_2018-04-09_13-09-42.png

Si prefija un número de versión con el símbolo ^, la versión menor y el número de actualización podrían cambiar cada vez que ejecute el comando install.

Luego, tenemos que instalar las nuevas dependencias usando:

1
npm install

Además de instalar las librerías en node_modules, también hay que copiar a dist/lib las librerías que se utilizan en las vistas Razor y por esto, una de las tareas de build-aspnetcore es copiar todos los archivos de node_modules referenciados en las vistas, a la carpeta lib.

Para esto creamos el archivo vendors.html (o cualquier otro) en la carpeta de las vistas de CoreUI para incluir las referencias que vamos a usar desde las vistas Razor de la aplicación, así:

vendors.html
[AspNetCore2CoreUI-2.0] src\CoreUI\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>Vendor list</title>
</head>

<body style="font-family: Arial, Helvetica, sans-serif; font-size: 18px;">

<h3>Files to deploy to dist/lib</h3>
<ul>
  <li>"lib/jquery-validation/dist/jquery.validate.min.js"</li>
  <li>"lib/jquery-validation/dist/additional-methods.js"</li>
  <li>"lib/jquery-validation/dist/localization/messages_es.js"</li>
  <li>"lib/jquery-validation-unobtrusive/dist/jquery.validate.unobtrusive.min.js"</li>
</ul>

</body>

</html>

Este archivo será revisado con el comando build/build-aspnetcore, igual que todas las vistas de CoreUI, para seleccionar los archivos que se copiarán de node_modules a dist/lib.

Es importante (para que el script funcione) incluir la ruta relativa y el nombre del archivo, desde la carpeta de inicio, incluyendo la misma carpeta “node_modules”, entre comillas.

El programa también incluirá el archivo .map relacionado (si existe).

Así que ahora podemos crear/actualizar la carpeta de distribución con:

1
npm run build-aspnetcore

Gestores de paquetes client-side.

  • En algún momento usted podría querer usar algún gestor de paquetes especializado del lado del cliente, como WebPack, pero no vamos a cubrir eso en este artículo.

2.5 - Copiar la carpeta de distribución en la solución

Ahora copiaremos el contenido de la carpeta dist en la nueva carpeta src\CoreUI de nuestra solución.

El src\CoreUI será nuestra carpeta de referencia que usaremos para comparar con las nuevas versiones de CoreUI, cuando estén disponibles, para actualizar los componentes de nuestra aplicación según sea necesario.

La solución VS debería verse así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/explorer_2018-05-11_18-08-35.png

En un momento fusionaremos esa carpeta src\CoreUI a las carpetas wwwroot y Views de nuestra aplicación.

Este es un momento excelente para guardar el proyecto en su repositorio local!

src\CoreUI no es parte de la solución en Visual Studio.

  1. Note que, aunque src\CoreUI está dentro de la estructura de carpetas de la solución y bajo control de versiones, no es parte de la solución de Visual Studio, es decir, no lo verá en el explorador de la solución.

3 - Integrar la carpeta de referencia CoreUI en la aplicación MVC

Primero haremos una integración básica, sólo para verificar que todas las vistas de Razor funcionen correctamente:

  1. Copiar todos los archivos estáticos, que no sean .html, a la carpeta wwwwroot.
  2. Crear un controlador genérico para mostrar todas las vistas de Razor
  3. Copiar las vistas Razor a la carpeta Views del controlador

Luego reorganizaremos las vistas usando parciales, para que se parezca más a una aplicación estándar de Razor MVC.

Aquí es donde una herramienta como Beyond Compare resulta muy útil, especialmente a la hora de actualizar los archivos a nuevas versiones de CoreUI.

3.1 - Copiar archivos estáticos a la carpeta wwwroot

Así que tenemos que copiar estas carpetas de src\CoreUI a src\CoreUI.Mvc\wwwwroot:

  • css
  • imágenes
  • js
  • vendors

Esta carpeta vendors en realidad contiene archivos css específicos de CoreUI, pero no quería cambiar ninguno de los scripts estándar de la plantilla.

Si se utiliza Beyond Compare, el resultado debería ser algo así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/BCompare_2018-05-11_18-36-03.png

3.2 - Crear un controlador genérico para las vistas CoreUI

A continuación crearemos un controlador simple para mostrar cualquiera de las vistas Razor de CoreUI (*.cshtml), que sólo recibe el nombre de la vista a mostrar.

CoreUIController.cs
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Controllers\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace CoreUI.Mvc.Controllers
{
    [Route("CoreUI")]
    public class CoreUIController : Controller
    {
        [Route("{view=Index}")]
        public IActionResult Index(string view)
        {
            ViewData["Title"] = "CoreUI Free Bootstrap Admin Template";

            return View(view);
        }
    }
}

También necesitamos crear la carpeta Views\CoreUI correspondiente, para las vistas Razor de este controlador.

3.3 - Copiar las vistas de Razor a la carpeta Views\CoreUI

Usando BeyondCompare copie las vistas de Razor generadas desde la carpeta de referencia CoreUI a la carpeta Views\CoreUI:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/BCompare_2018-05-11_19-03-04.png

3.4 - Ejecute la aplicación

Ahora debería poder ejecutar la aplicación con [Ctrl]+[F5] y al navegar a https://localhost:#####/CoreUI/Index (###### = puerto asignado por VS) para obtener algo así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-05-11_20-13-18.png

Debería poder navegar a cualquier página de la plantilla y todas las peticiones serán manejadas por el controlador, lo que puede verificar en la barra de direcciones.

Una vez más, este es un buen momento para comprometer tu trabajo.

3.5 - Crear una vista _Disposición

Cuando se trabaja en Razor, la página renderizada normalmente tiene, al menos, dos partes:

  1. El contenido, que es el núcleo de cualquier cosa que quieras mostrar en un momento dado, por ejemplo, la página de índice, y puede llamarse de cualquier manera que tenga sentido, por ejemplo, Index.cshtml.

  2. El layout, que “rodea” el contenido y se suele llamar _Layout.cshtml, pero no es más que otra vista de Razor que usamos de forma diferente.

Correlacionando esto con las vistas de CoreUI Razor generadas, es fácil darse cuenta que para cualquier vista (excepto 404, 500, login y registro):

El layout es equivalente a blank.cshtml. El contenido es equivalente a la diferencia entre la vista y blank.cshtml.

Así que empecemos copiando blank.cshtml a _Layout.cshtml y añadiendo el render body helper en _Layout.cshtml así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-05-11_22-06-37.png

En ASP.NET MVC, cuando solicitamos una vista del controlador, el motor de renderizado:

  1. Encuentra la vista solicitada
  2. Encuentra el layout configurado para la vista
  3. Presenta el layout insertando el contenido de la vista en el helper @RenderBody().

Así que vamos a comparar ahora blank.cshtml (izquierda) con index.cshtml (derecha), debería obtener algo como esto:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/BCompare_2018-05-11_20-51-32.png

OEn la vista de miniaturas de la izquierda podemos identificar cuatro zonas:

  1. Antes de la zona de contenido del índice, ambos archivos son idénticos
  2. En la zona de contenido del índice el blank.cshtml no tiene líneas
  3. Después de la zona de contenido del índice, ambos archivos son idénticos de nuevo
  4. Hay algunas líneas adicionales al final del archivo index.cshtml.

Así que al borrar las líneas comunes de las zonas 1, 2 y las dos últimas líneas en el archivo index.cshtml (a la derecha) debería llegar a esto:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/BCompare_2018-05-11_21-48-08.png

Observe las cuatro líneas al final que existen sólo en index.cshtml.

La forma de resolver esto es creando una sección Scripts en el archivo index.cshtml y añadiendo una llamada al helper RenderSection en el archivo _Layout.cshtml.

Después de arreglar eso, las últimas líneas de Index.cshtml deberían ser:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-05-11_21-59-24.png

Y ahora las últimas líneas de _Layout.cshtml deberían ser:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/devenv_2018-05-11_22-03-47.png

Por lo tanto, si ahora ejecutamos la aplicación de nuevo y refrescamos la página https://localhost:#####/CoreUI/Index, deberíamos obtener algo así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-04-10_21-34-56.png

Que se ve igual que antes, sólo que esta vez hemos separado el contenido del layout.

Pruebe comentar la línea @RenderBody() que agregamos a _Layout.cshtml para comprobar lo que sucede, en caso de que no esté claro en este punto.

También puede buscar los comentarios del marcador de contenido que agregamos a _Layout.cshtml.

Este es otro buen momento para guardar su trabajo

3.6 - Convertir el resto de las páginas de CoreUI

Ahora puede repetir el proceso con el resto de las páginas de CoreUI, a excepción de las páginas 404, 500, login y register, que no tienen layout.

Hay un par de detalles adicionales, pero no voy a cubrirlos aquí, puede revisar las vistas finales en el repositorio.

3.7 - Componentizar la vista _Layout

No es práctico tener una vista _Layout masiva de más de 700 líneas, por lo que es mejor dividirla en componentes más pequeños.

No voy a pasar por todo el proceso aquí, sino que sólo mostraré el resultado final, incluyendo la fusión con el archivo _Layout por defecto de ASP.NET Core MVC, que puede encontrar en la carpeta Views\Shared y puede revisar todos los detalles en el repositorio del artículo:

_Layout.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Views\Shared\
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<!DOCTYPE html>
<!--
* CoreUI - Free Bootstrap Admin Template
* @@version v2.0.0
* @@link https://coreui.io
* Copyright (c) 2018 creativeLabs Łukasz Holeczek
* Licensed under MIT (https://coreui.io/license)
*
* Adaptated to ASP.NET Core MVC 2.1 by Miguel Veloso
* http://coderepo.blog
-->

<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
  <meta name="description" content="CoreUI - Open Source Bootstrap Admin Template">
  <meta name="author" content="Łukasz Holeczek">
  <meta name="keyword" content="Bootstrap,Admin,Template,Open,Source,jQuery,CSS,HTML,RWD,Dashboard">
  <title>@ViewData["Title"] - CoreUI.Mvc</title>

  <!-- Icons-->
  <link href="~/lib/@@coreui/icons/css/coreui-icons.min.css" rel="stylesheet">
  <link href="~/lib/flag-icon-css/css/flag-icon.min.css" rel="stylesheet">
  <link href="~/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
  <link href="~/lib/simple-line-icons/css/simple-line-icons.css" rel="stylesheet">

  <environment include="Development">
    <!-- Template styles -->
    <link href="~/css/style.css" rel="stylesheet">
    <link href="~/vendors/pace-progress/css/pace.css" rel="stylesheet">
    <!-- styles tweaks -->
    <link rel="stylesheet" href="~/css/site.css">
  </environment>

  <environment exclude="Development">
    <!-- Template styles -->
    <link href="~/css/style.min.css" rel="stylesheet" asp-append-version="true">
    <link href="~/vendors/pace-progress/css/pace.min.css" rel="stylesheet" asp-append-version="true">
    <!-- styles tweaks -->
    <link href="~/css/site.min.css" rel="stylesheet" asp-append-version="true">
  </environment>

</head>
<body class="app header-fixed sidebar-fixed aside-menu-fixed sidebar-lg-show bg-gray-200">

  <!-- APP-HEADER-->
  <partial name="_app-header" />
  <!-- /APP-HEADER-->

  <partial name="_CookieConsentPartial" />

  <div class="app-body">
    <div class="sidebar">

      <!-- SIDEBAR-NAV -->
      <partial name="_sidebar-nav" />
      <!-- /SIDEBAR-NAV -->

      <button class="sidebar-minimizer brand-minimizer" type="button"></button>
    </div>
    <main class="main">

      <!-- VIEW-BREADCRUMBS -->
      @RenderSection("Breadcrumbs", required: false)
      <!-- /VIEW-BREADCRUMBS -->

      <div class="container-fluid">

        <!-- VIEW-STYLES -->
        @RenderSection("Styles", required: false)
        <!-- /VIEW-STYLES -->

        <div class="animated fadeIn">

          <!-- VIEW-CONTENT -->
          @RenderBody()
          <!-- /VIEW-CONTENT -->

        </div>

        <!-- VIEW-MODALS -->
        @RenderSection("Modals", required: false)
        <!-- /VIEW-MODALS -->

      </div>
    </main>

    <!-- ASIDE-MENU -->
    <partial name="_aside-menu" />
    <!-- /ASIDE-MENU -->

  </div>
  <footer class="app-footer">
    <div>
      <a href="https://coreui.io">CoreUI</a>
      <span>&copy; 2018 creativeLabs.</span>
    </div>
    <div class="ml-auto">
      <span>Powered by</span>
      <a href="https://coreui.io">CoreUI</a>
    </div>
  </footer>

  <environment include="Development">
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
  </environment>
  <environment exclude="Development">
    <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
            asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
            asp-fallback-test="window.jQuery"
            crossorigin="anonymous"
            integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
    </script>
  </environment>

  <script src="~/lib/popper.js/dist/umd/popper.min.js"></script>
  <script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
  <script src="~/lib/pace-progress/pace.min.js"></script>
  <script src="~/lib/perfect-scrollbar/dist/perfect-scrollbar.min.js"></script>
  <script src="~/lib/@@coreui/coreui/dist/js/coreui.min.js"></script>

  <environment include="Development">
    <script src="~/js/site.js" asp-append-version="true"></script>
  </environment>
  <environment exclude="Development">
    <script src="~/js/site.min.js" asp-append-version="true"></script>
  </environment>

  <!-- VIEW-SCRIPTS -->
  @RenderSection("Scripts", required: false)
  <!-- /VIEW-SCRIPTS -->

</body>
</html>

Vale la pena notar que los Breadcrumbs son manejados como una sección en la vista, más que como una vista parcial, porque probablemente están vinculados a la vista. En caso de que no lo sean, ahora debería poder adaptarlo a sus necesidades.

De todos modos veremos en un momento sobre una forma interesante de manejar esto usando layouts anidados.

Nuevamente, este es un buen momento para salvar su trabajo

4 - Integrar las vistas CoreUI y la aplicación MVC

Sólo faltan unos pocos pasos para terminar la integración con la aplicación ASP.NET Core MVC.

  1. Mover _Layout.cshtml y las parciales a la carpeta **Views\Shared

  2. Mostrar las vistas MVC estándar con el nuevo _Layout.cshtml.

  3. Integrar las vistas de Account con la plantilla CoreUI

El ítem #1 es algo trivial, sólo vale la pena notar que la vista _app-app-header-nav.cshtml contendrá ahora el menú original de ASP.NET Core MVC:

_app-header-nav.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Views\Shared\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<ul class="nav navbar-nav d-md-down-none">
  <li class="nav-item px-3">
    <a asp-area="" asp-controller="Home" asp-action="Index">Home</a>
  </li>
  <li class="nav-item px-3">
    <a asp-area="" asp-controller="Home" asp-action="About">About</a>
  </li>
  <li class="nav-item px-3">
    <a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a>
  </li>
</ul>

Usted puede, por supuesto, ajustar esto a lo que mejor se adapte a sus necesidades.

También vale la pena señalar aquí, que el elemento #2 sólo ocurre porque el layout de las vistas está configurado para ser _Layout.cshtml en:

_ViewStart.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Views\
1
2
3
@{
    Layout = "_Layout";
}

Pero no queremos (sólo por diversión) mostrar la vista de breadcrumbs en las vistas estándar de ASP.NET MVC.

Resolveremos esto usando “nested layouts” para probar una característica interesante de ASP.NET MVC.

4.1 - Aplicación de layouts anidados para breadcrumbs

Al dividir el diseño, se hizo evidente que era necesario algo especial para manejar los breadcrumbs, ya que son algo que tiene que adaptarse al contexto, probablemente para cada vista.

Así que era obvio que los breadcrumbs deberían ser una sección de la vista, pero añadirlo a todas las vistas de CoreUI era un poco tedioso.

Así que una solución interesante para esto fue añadir un layout local en la carpeta Views\CoreUI para incluir los breadcrumbs y separar los elementos y el menú de los breadcrumbs, así:

_CoreUILayout.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Views\CoreUI\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@{ Layout = "_Layout"; }

@* view-styles *@
@section Styles {
  @RenderSection("Styles", required: false)
}

@*view-breadcrumbs*@
@section Breadcrumbs {
  <ol class="breadcrumb">

    <!-- BREADCRUMB-ITEMS -->
    <partial name="_breadcrumb-items" />
    <!-- /BREADCRUMB-ITEMS -->

    <!-- BREADCRUMB-MENU -->
    <partial name="_breadcrumb-menu" />
    <!-- /BREADCRUMB-MENU -->

  </ol>
}

@RenderBody()

@* view-modals *@
@section Modals {
  @RenderSection("Modals", required: false)
}

@* view-scripts *@
@section Scripts {
  @RenderSection("Scripts", required: false)
}

Para configurar el layout para todas las vistas CoreUI, sólo necesitamos añadir este archivo en la carpeta Views\CoreUI:

_ViewStart.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Views\CoreUI\
1
@{ Layout = "_CoreUILayout"; }

Así es como estas partes trabajan juntas en la carpeta Views\CoreUI:

  1. El contenido de la vista se muestra en @RenderBody() en el layout _CoreUILayout.

  2. La sección Scripts se muestra en la línea 32 de _CoreUILayout.cshtml.

  3. Pero, como la línea 32 está dentro de otra sección Scripts, se renderizará en la línea 133 en _Layout.cshtml.

  4. Porque _Layout.cshtml es el layout para la vista _CoreUILayout.cshtml, tal y como se configuró en su primera línea.

De esta manera, cualquier vista puede definir una sección Breadcrumbs, igual que las líneas 9-21 en _CoreUILayout.cshtml, y esto podría ser:

  1. Una vista parcial local (p. ej. _breadcrumb-items)
  2. Una vista compartida (ej. _breadcrumbs-menu)
  3. Sólo el markup html requerido justo ahí o
  4. No usar breadcrumbs en absoluto, como en las vistas iniciales de Razor creadas por VS.

Un último detalle, para manejar correctamente los breadcrumbs de esta manera, es necesario añadir un pequeño ajuste a la css en src\CoreUI.Mvc\wwwroot\css\site.css:

1
2
3
.container-fluid > .animated {
    margin-top: 24px !important;
}

Por lo tanto, no es de extrañar que esta sea la vista blank.cshtml resultante, destacando que todas las secciones que se muestran son sólo marcadores y opcionales, es decir, se pueden omitir por completo.

blank.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Views\CoreUI\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@* view-styles *@
@section Styles {
}

@*view-breadcrumbs*@
@section Breadcrumbs {
}

@* view-content *@

@* view-modals *@
@section Modals {
}

@* view-scripts *@
@section Scripts {
}

Si ahora regresamos a https://localhost:#####/CoreUI/Index, veremos la misma vista, pero esta vez como una composición del contenido principal del layout y de las vistas parciales.

Y ahora con el menú MVC en la barra superior y los breadcrumbs sólo en las vistas CoreUI.

4.2 - Integrar las vistas “Account” de Identity

Personalizanfo las vistas de Identity 2.1.

  • Comenzando con ASP.NET Core 2.1 hay una nueva característica que permite incluir vistas de Razor en librerías de clases, por lo que las vistas ya no se generan, y por lo tanto debe seguir este procedimiento para personalizarlas en caso de que lo necesite.

Sólo falta un paso más para integrar las vistas estándar de Identity con CoreUI.

No voy a entrar en detalles aquí, pero los pasos de “alto nivel”, usando _LoginPartial.cshtml como guía, son: _LoginPartial.cshtml:

  1. Mostrar todos los elementos relacionados con el usuario en la parcial _app-header.cshtml sólo cuando el usuario está conectado y
  2. Agregar enlaces a las opciones de Profile y Logout en la parcial _user-nav.cshtlm y, finalmente
  3. Eliminar _LoginPartial.cshtml

Así que el resultado final, cuando el usuario no está conectado debería ser así:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-05-21_13-23-35.png

4.3 - Personalizar vistas de identidad

Desde VS 2017 v15.7 y posteriores, las plantillas de proyecto ASP.NET Core MVC utilizan las vistas de identidad por defecto del paquete Microsoft.AspNetCore.Identity.UI así que fue necesario personalizar un poco siguiendo las instrucciones en https://blogs.msdn.microsoft.com/webdev/2018/04/12/asp-net-core-2-1-0-preview2-now-available/#user-content-customize-default-identity-ui.

Para mostrar las opciones de navegación en la vista de perfil de usuario fue necesario personalizar la vista AccountManageManageManageNav para aplicar las clases CoreUI correctas de esta manera:

_ManageNav.cshtml
[AspNetCore2CoreUI-2.0] src\CoreUI.Mvc\Areas\Identity\Pages\Account\Manage\
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@inject SignInManager<IdentityUser> SignInManager
@{
    var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<ul class="nav nav-pills flex-column">
    <li class="nav-item"><a class="nav-link @ManageNavPages.IndexNavClass(ViewContext)"asp-page="./Index">Profile</a></li>
    <li class="nav-item"><a class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)" asp-page="./ChangePassword">Password</a></li>
    @if (hasExternalLogins)
    {
        <li class="nav-item"><a class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)" asp-page="./ExternalLogins">External logins</a></li>
    }
    <li class="nav-item"><a class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)" asp-page="./TwoFactorAuthentication">Two-factor authentication</a></li>
    <li class="nav-item"><a class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)" asp-page="./PersonalData">Personal data</a></li>
</ul>

Además de algunos otros detalles que puede revisar mejor en el repositorio.

Para obtener una vista del perfil de usuario como esta:

Construyendo aplicaciones elegantes con ASP.NET Core MVC 2.1 y CoreUI 2 (Bootstrap 4) /posts/images/chrome_2018-05-21_17-05-58.png

Así que, en este punto, creo que llegamos a un buen punto de partida para tener una interfaz de usuario elegante y atractiva para su próximo proyecto.

Resumen

En este artículo estudiamos en detalle el proceso de adaptación de la última versión de la plantilla HTML CoreUI para facilitar el desarrollo de aplicaciones atractivas en ASP.NET Core MVC 2.1.


Espero que este artículo le haya resultado útil y le invito a darme su opinión en la sección de comentarios.

Gracias,

Miguel.

Enlaces relacionados

.NET Core 2.1.0-rc1 with SDK 2.1.300-rc1 - x64 SDK Installer
https://download.microsoft.com/download/B/1/9/B19A2F87-F00F-420C-B4B9-A0BA4403F754/dotnet-sdk-2.1.300-rc1-008673-win-x64.exe)

Beyond Compare, from Scooter Software
http://www.scootersoftware.com/

Bootstrap 4.1
https://getbootstrap.com/docs/4.1/getting-started/introduction/

CoreUI 2.0.0 in GitHub
https://github.com/coreui/coreui-free-bootstrap-admin-template/tree/v2.0.0

CoreUI build-aspnetcore PR in GitHub
https://github.com/coreui/coreui-free-bootstrap-admin-template/pull/379

Customize default ASP.NET Core 2.1 Identity UI
https://blogs.msdn.microsoft.com/webdev/2018/04/12/asp-net-core-2-1-0-preview2-now-available/#user-content-customize-default-identity-ui

EditorConfig Language Service for Visual Studio
https://marketplace.visualstudio.com/items?itemName=MadsKristensen.EditorConfig

Node
https://nodejs.org/

npm
https://www.npmjs.com/

Razor tag helpers
https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-2.1