.NET Core 2 – Proyecto básico – Parte 1

En mi cruzada por moverme desde PHP+Symfony a otro framework basado en C#, me encontré por ahí con Core 2 y me pareció más que interesante, no sólo por el lenguaje y por ser promovido por Microsoft, sino sobre todo por la portabilidad, algo a lo que no nos tenían acostumbrados.

Lo siguiente es una guía básica de como crear un proyecto básico y mínimo a fin de que sirva como base. En este caso particular se muestra como realizarlo usando Visual Studio 2017 y tomando algunas decisiones que son de diseño y no estrictamente necesarias por el framework. Para una introducción más conceptual a ASP.NET Core lo mejor es dirigirse directamente al sitio oficial: https://docs.microsoft.com/en-us/aspnet/core/.

Comenzamos por crear un proyecto basado en la plantilla “ASP.NET Core Web Application”:

Tomaremos como base un simple proyecto tipo vidriera cuyo objetivo será mostrar una lista de productos de entre los cuales el cliente podrá visualizar su imagen, el valor y una descripción, además de aportar algo de feedback al vendedor. La aplicación incluirá un mecanismo simple de autenticación. Además, y si bien no es estrictamente necesario, en este proyecto usaremos el patrón MVC.

Al crear un nuevo proyecto VS2017 nos da la opción de seleccionar diferentes plantillas para incluir automáticamente: MVC, Angular o ReactJS, por ejemplo. En este caso partiremos de la plantilla vacía para poder entender la estructura de la aplicación.

Una vez seleccionadas las opciones VS2017 creará un proyecto ASP.NET Core vacío con la siguiente estructura que se ve en la siguiente imagen.

  • Dependencies: Dentro de esta carpeta veremos las dependencias del proyecto. ASP.NET Core es un paquete NuGet y, por lo tanto, veremos un metapaquete bajo esta carpeta, “Microsoft.AspNetCore.All”, que a su vez referencia todos los paquetes pertenecientes a ASP.NET Core. Estas referencias también pueden verse en claro XML si editamos el archivo BizShowcase.csproj.
  • wwwroot: Web root del proyecto, aquí guardaremos archivos estáticos para referenciarlos directamente.
  • Program.cs: Punto de entrada de la aplicación. ASP.NET Core es una aplicación de consola, de modo que veremos el método Main en esta clase. En esta clase se configura el servidor por defecto: Kestrel, un servidor interno que ejecutará la aplicación (este servidor puede usarse en combinación con IIS, apache o nginx).
  • Startup.cs: Clase de configuración de la aplicación. Se realizan principalmente dos cosas:
    • Se define el “request pipeline”, una cadena de componentes que se ejecutarán en orden para cada petición que se realice a la aplicación. Esta capa también es llamada “middleware”.
    • Se configuran los servicios que se utilizarán en la aplicación, y que luego se utilizarán utilizando el patrón de “inyección de dependencias“.

Configurando la aplicación

Comenzaremos configurando lo básico dentro de Startup.cs. Lo primero que haremos es habilitar MVC. ASP.NET Core es un framework muy liviano y, por lo tanto, casi no hay características habilitadas por defecto.

Para habilitar MVC utilizamos el método ConfigureServices de la clase Startup y agregamos la línea:

Con esto agregamos el servicio a la colección de servicios administrados por el motor de inyección de dependencias.

A continuación configuramos la cadena de componentes que manejarán las peticiones HTTP:

  • UseDeveloperExceptionPage es un componente que nos permite ver los errores en forma algo más detallada, lo que se conoce en ASP como la “pantalla amarilla de la muerte“. Este componente únicamente debe utilizarse durante el desarrollo y no en el deploy final para no exponer información del servidor y la aplicación a los internautas.
  • UseStatusCodePages nos permite ver de forma textual códigos de error de tipo 400 y 500.
  • UseStaticFiles permite que la aplicación sea capaz de servir archivos estáticos (js, css, png, etc.).
  • UseMvcWithDefaultRoute. Si la petición llega a este punto entonces comienza a manejarse por el módulo de MVC siguiendo los patrones y estructuras que veremos a continuación.

Creando la primer página en ASP.NET Core 2

Vamos a estructurar la aplicación utilizando el patrón MVC. Esto no es necesario para realizar una aplicación pero es un patrón de diseño que me resulta claro y efectivo a la hora de desarrollar aplicaciones web. En resumen: la petición llega a un Controlador, el cual se vale del Modelo de datos para renderizar una Vista. De esta forma el Controlador se encarga de la lógica y gestión, el Modelo representa los datos de la aplicación y la Vista es la interfaz con la que el usuario interactúa.

Modelo

El modelo se compondrá del dominio de datos y de la lógica para gestionar estos datos, no así de la lógica y manipulación de los datos desde el punto de vista del negocio, esto último será tarea del controlador. La idea es disponer de una clase para los datos y otra clase que encapsule a la aplicación el manejo o persistencia de esos datos.

Para el modelo de datos se usaran objetos POCO (plain old C# objects), los cuales crearemos en la subcarpeta Models, que actuará a su vez de namespace, para organizar mejor el código:

Sin embargo esta clase sola no es suficiente, necesitamos una clase que gestione la persistencia de los datos. Para ello vamos a crear primero una interfaz que defina la estructura de esa clase:

Y luego, crearemos una clase de prueba, ya que no voy a crear una base de datos en este momento:

Finalmente, necesitamos registrar nuestros servicios para que actúen también por inyección de dependencias y así tengamos objetos menos acoplados. Para ello agregamos lo siguiente en la clase Startup:

AddTransient quiere decir que cada vez que algún objeto requiera un IProductoRepo se creará un nuevo MockProductoRepo, es decir siempre se obtendrá una instancia nueva. De igual manera existe AddSingleton, que quiere decir que sólo una instancia del objeto podrá estar vigente durante la vida de la aplicación, y AddScoped, la cual crear una sola instancia pero por petición, cada petición tendrá su propia instancia.

Más adelante cuándo implementemos una base de datos y definamos el mecanismo de persistencia, crearemos una nueva versión de esta clase, SQLProductoRepo, por ejemplo, y regresaremos a Startup para reemplazar MockProductoRepo.

Controlador

El controlador es el administrador del patrón MVC, debe responder a las peticiones del usuario y actualizar el modelo en consecuencia.

Para crear el controlador, al igual que con el modelo, crearemos una carpeta Controllers dentro del proyecto, y dentro de ella la clase HomeController que heredará de Controller:

Al recibir una petición el módulo Mvc elige un Controlador para gestionar la petición y es un método, también llamada Action, de este controlador quién ejecuta la lógica con la que se tratará la petición. Ese método o Action devolverá una vista como resultado que se renderizará en el explorador del usuario.

Por supuesto, no podemos avanzar mucho más sin la vista.

Vista

La vista es una plantilla que contiene definiciones para la presentación de la información y código dinámico orientado a esa tarea. Usarán la extensión .cshtml, lo que ya nos da una idea básica de lo que contiene: código en C# y HTML. Esta sintaxis se llama Razor. Por supuesto, también es posible entregar páginas estáticas.

Por convención, las vistas se almacenarán en la subcarpeta Views y dentro de ella en una sucarpeta con el nombre de la clase controlador que la invoca, sin la palabra Controller. Para el ejemplo del apartado anterior la carpeta se llamaría Home. Nuevamente, por convención, dentro de esa carpeta la vista que se renderizará será la que tenga por nombre el nombre del método que la invoca, por ejemplo: Index.cshtml. Si tal vista no es encontrada se lanzará una excepción.

Para hacer una prueba simple y cerrar el circuito vamos a agregar la siguiente línea en el controlador:

Y dentro de la carpeta Views/Home creamos el archivo Index.cshtml con el siguiente contenido:

Ahora ya estamos en condiciones de ejecutar la aplicación y si, no es ninguna sorpresa, veremos “Hola mundo!” en el navegador.

ViewBag es una de las formas de pasar datos entre el controlador y la vista, dentro del objeto podemos crear dinámicamente tantos parámetros como deseemos (ya que ViewBag es dynamic) y ya vemos la sintaxis de Razor que nos permitirá acceder al objeto, simplemente precediendo el parámetro con el caracter arroba (@).

Sin embargo, la mayor parte de las vistas que querremos usar serán fuertemente tipadas ya que será conveniente pasar un modelo. Modificamos entonces la acción como sigue:

De esta forma pasamos la lista de productos a la vista, la cual ahora adopta la siguiente forma:

Algunas cuestiones para notar aquí:

  • En la primera línea indicamos el tipo que tendrá el modelo, el cual luego será referenciado por Model
  • Utilizamos ViewBag como antes para mostrar esta vez el título
  • Utilizamos la sintaxis Razor para hacer un loop por todos los productos y mostrar el nombre y precio de cada uno de ellos

Un detalle a notar es que esta vista contiene todo el código html de la página, lo cual no sería una buena práctica en un sitio grande y sólo deberíamos incluir en la vista el código que hace a la vista y dejar todo el marco, menúes, etc. para las plantillas. .Net Core 2 dispone de dos convenciones que nos llevarán a tal fin:

  • _Layout.cshtml es un archivo especial que se utilizará como plantilla y ya que será utilizado por varias vistas se coloca en una carpeta especial llamada Shared, también dentro de Views.
  • _ViewStart.cshtml es un archivo especial que se carga antes que cualquier vista. Lo utilizaremos para indicar cual es la plantilla a utilizar.

Entonces creamos el archivo _Layout.cshtml dentro de la carpeta Shared (la cual creamos a su vez dentro de Views):

En donde @RenderBody() será el punto donde se insertará la vista. Por supuesto, ya podemos quitar de Index.cshtml todo el código html sobrante y sólo quedarnos con el contenido.

A su vez, bajo Views creamos _ViewStart.cshtml para indicar en cada vista cual es la plantilla que debe utilizarse:

Si ahora corremos la aplicación veremos la lista de productos.

Básicamente ya tenemos resuelto el tema, sin embargo esto podría mejorarse un poco más. Estamos usando en este momento dos métodos para pasar información a la vista: ViewBag y el modelo. ¿No sería posible tener un tipo de dato que incorpore toda la información que precisa la vista? ¿Algo así como un modelo de la vista?

Resulta que no sólo es posible, sino muy común. Utilizaremos entonces la carpeta ViewModels para almacenar este tipo de información:

Entonces modificamos la acción del controlador de la siguiente manera:

Por supuesto, ahora el tipo del modelo en la vista ha cambiado, de modo que ajustamos la vista como sigue:

Dando estilo a la vista

Si bien la página muestra la información que queremos, el último detalle sería darle algo de estilo visual, ya que las aplicaciones no sólo tienen que ver con lo funcional sino también con lo estético. Para ello añadiremos Bootstrap.

Actualmente para agregar paquetes del lado del cliente .Net Core 2 utiliza Bower (Microsoft ha anunciado, sin embargo, que cambiará a npm). Lo que sigue es el procedimiento para añadir bootstrap utilizando Bower:

  1. Agregamos el archivo bower.json al proyecto, agregando un nuevo item al proyecto y buscando por bower, aparecerá “Bower Configuration File”.
  2. En bower.json, dentro de “dependencies” agregamos: “bootstrap”: “v3.3.7”
  3. Apenas grabamos el archivo automáticamente se descargará bootstrap y todas sus dependencias y si miramos la carpeta wwwroot veremos que se crea la subcarpeta “lib” y dentro de ella las subcarpetas “bootstrap” y “jquery”.

Dentro de wwwroot agregamos la carpeta “images” y allí colocaremos algunas imágenes para ilustrar los productos.

Creamos también una carpeta “content” y dentro el archivo site.css:

Por supuesto, ahora tengo que referenciar esta hoja de estilo, al igual que bootstrap, en la plantilla y aprovecho para agregar algunas clases de bootstrap:

Finalmente, modifico la vista para mejorar el aspecto visual:

Si ejecutamos una vez más la aplicación obtendremos el siguiente resultado:

Conclusión

Por supuesto para realizar una aplicación completa aún falta bastante, pero esto puede dejar una clara idea de como se estructura una aplicación .Net Core 2 y cual es su potencial. Desde mi punto de vista lo que han logrado con este framework es muy interesante y ciertamente prefieron desarrollar aplicaciones web en C# en lugar de en PHP. Seguramente en algunos días volveré sobre este tema y agregaremos a esta aplicación la conexión con una base de datos real.