[SPA] Scaffolding de una solución con dotnet CLI

Cuando vas trabajando en diferentes proyectos y además algunas veces te toca hacer arquitectura, llega un momento en que te das cuenta que estaría muy bien crear un template de una solución con sus proyectos y dependencias.

Más de una vez quise crear un template en visual studio que tuviera lo típico que necesitas para hacer una solución en tres capas. Las veces que lo quise hacer me encontré con un problema, la relación coste/beneficio. Es muy costoso crear un template de una solución - ya lo es el template de un proyecto - el tiempo de utilidad podría ser relativamente poco (piensa las veces que ha cambiado desde Visual Studio 2012 al Visual Studio 2017 la creación de un proyecto web). Además Visual Studio cambia el soporte a los templates arbitrariamente entre versión y versión. Después apareció yeoman con sus generadores y me olvidé un poco de esto.

Dotnet CLI... to the rescue

Pero al ver lo que se puede hacer desde la línea de comandos de dotnet cli, lo retome con nuevas esperanzas. Y quiero compartir mis resultados.

Lo primero, mi problema sobre el coste beneficio se resolvió de pleno. Tarde 30 minutos en ver que era viable y 3 horas hasta tener el script que te muestro. Y a diferencia de un template de Visual Studio, esto también me funciona en Mac y Linux.

La idea es crear el esqueleto de una backend típico en .net como puede ser una arquitectura de 3 capas.

Los requerimientos son:

  1. La solución tiene que tener los siguientes proyectos:

    • web api,
    • Mensajes usados en la firma del web api
    • application layer,
    • business layer,
    • data layer,
    • entidades,
    • proyectos de pruebas.
  2. Todos los proyectos deberán estar asociados a la solución.
  3. Cada proyecto tendrá las referencias a los otros proyectos que usa. Además, cuando sea necesario tendrán referencias que estén en nuget.
  4. Además, quiero que cuente con una estructura de directorios que separe el código de pruebas del código de aplicación.
  5. Otra de las cosas que me toca agregar a los proyectos es el gitignore, así que me lo descargaré del repositorio que está en GitHub donde hay diferentes gitignore dependientes de la herramienta de desarrollo que uses.
  6. Restaurar las referencias de todos los proyectos
  7. Compilare la solución. No solo un proyecto.
  8. Abrir la solución con Visual Studio Code.

La idea final es abrir un bash y escribir "Bash crearBackend3Capas.sh NombreSolucion".

¿Que necesitas tener instalado?

  • .Net Core
  • El último SDK de .net core.
  • Si tienes algún problema, bájate el último build de dotnet cli desde las release del repositorio en GitHub.

¡¡Vamos a por ello!!

Si quieres seguir el artículo con el código descargado, lo tienes en este GitHub.

Declaración de variables

Tomamos el nombre de la solución que se puso como parámetro y creamos el archivo de la solución dentro de una carpeta con el mismo nombre. Si la solución se llama "CodeCrafters", quedará "CodeCrafters/CodeCrafters.sln". Igual que si lo hicieras con Visual Studio.

Por cada proyecto uso tres variables para

  • el nombre del proyecto
  • la carpeta donde se pondrá el proyecto
  • el path donde estará el archivo del proyecto

Recordar que en este punto ya estoy cumpliendo el requisito de colocar el código en un directorio y los test en otro. El código irá a src y las pruebas a test

SolutionName=$1;  
SolutionFile="$SolutionName/$SolutionName.sln";  
gitIgnorePath="$SolutionName/.gitignore";  
projExt=".csproj";

WebApiName="$SolutionName.WebApi";  
WebApiPath=${SolutionName%%/}/src/$WebApiName;  
WebApiProj=${WebApiPath%%/}/$WebApiName$projExt;  

Crear la solución

Le decimos a dotnet cli que nos cree una solución en un directorio llamado igual que la solución.

Un detalle, para poder diferenciar los pasos que se van ejecutan del script del resto de valores que se escribirán en la consola pongo los primeros de color verde claro.

echo -e "\033[1;92m Create solution \033[0m"  
dotnet new sln -n $SolutionName -o "$SolutionName"  

Crear los proyectos

En el script en GitHub tenes todos los proyectos, pero aquí pongo un ejemplo de los tres tipos de proyectos que se crean.

En cuanto a directorios, la idea es que el Proyecto de Web Api este en "CodeCrafters/src/CodeCrafters.WebApi/CodeCrafters.WebApi.csproj"

En todos estoy poniendo el mismo framework. En tu version 2.0 puedes hacer que el framework venga como un parámetro opcional. 😁

Los proyectos de tipo librería de clases pueden ser proyectos que referencien net Standart, puedes especificarle como framework el netstandard1.0 al 1.6

dotnet new webapi -n $WebApiName -o "$WebApiPath" -f netcoreapp1.1  
dotnet new classlib -n $AppLayerName -o "$AppLayerPath" -f netcoreapp1.1  
dotnet new xunit -n $AppLayerTestName -o "$AppLayerTestPath" -f netcoreapp1.1  

Poner un gitignore

Hay un repositorio en GitHub que tiene los diferentes gitignore según la herramientas que uses. Con la siguiente línea de comandos lo bajas de Github y lo grabas en la carpeta raíz de la solución.

curl -o $gitIgnorePath 'https://raw.githubusercontent.com/github/gitignore/master/VisualStudio.gitignore'  

Este mismo mecanismo te puede servir para otros archivos de uso común, como puede ser un archivo de settings de StyleCop.

Asociar los proyectos a la solución.

No puedes dejar los proyectos como islas, pertenecen a una solución y tienes que asociarlos. En esta línea de abajo buscas todos los proyectos y le ejecutas el comando que los asocia a la solución.

for refProj in `find $SolutionName -name '*.csproj'` ;  
  do dotnet sln $SolutionFile add $refProj ;  
done  

Nota: Este comando te puede servir para ejecutar todos los proyectos de test. Te invito a que te hagas un script que en tu ordenador compile y ejecute los test. Ya tienes el 50%, no te puedes quejar 😁

for unitTestProj in `find $SolutionName -name '*UnitTest.csproj'` ;  
  do dotnet test $unitTestProj ;  
done  

Referencias entre proyectos

Para indicar que el proyecto de WebApi necesita del proyecto de Business Layer tienes que ejecutar el siguiente comando

dotnet add $WebApiProj reference $BLayerProj  

Referencias externas

Puedes bajarte de un servidor de nuget los paquetes externos, pero primero mira que referencias trae en forma predeterminada cada proyecto. Por ejemplo, el proyecto de Web Api ya trae el paquete de MVC.

dotnet add $DALayerProj package Microsoft.EntityFrameworkCore --package-directory $SolutionName/packages  

Si buscas paquetes que no están en nuget debes especificar la url con el parámetro -s

dotnet add $DALayerProj package Microsoft.EntityFrameworkCore -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json  

Con lo que llevas hasta el momento ya tendrías suficiente, pero seguimos para matricula de honor. 👍

Restaurar paquetes

Los paquetes de nuget que tu necesitas ya se descargaron en el paso anterior, pero los que estan predeterminados en los proyectos, como Microsoft.AspNetCore no. Ahora toca descargarlos.

for proj in `find $SolutionName -name '*.csproj'` ;  
  do dotnet restore $proj ;  
done  

Compilar la solución

Acá hacemos un build de la solución, no solo de un proyecto. Al compilar ya detecta la dependencia entre proyectos.

dotnet msbuild $SolutionFile  

(opcional) Abrir la solución en Visual Studio Code

Si tienes VSCode en el path cargar la solución es facilísimo

code $SolutionName  

(recomendable) Subir una primera version a un git local

En Mac y Linux el git viene integrado en el bash, en windows tienes que instalarlo. La idea es que puedas iniciar un repositorio local de git y hacer un primer commit con la solución como quedo después de ejecutar todo el script.

pushd $SolutionName  
git init  
git add --all && git commit -m "Code generate by @CodeCraftersEs"  
popd  

"Pero Daniel... esto último no estaba entre los requerimientos..." Es que siempre me gusta sorprender a mis clientes dando algo mas de los que esperan. 😁

Conclusión

Hace tres años atrás hice una demo de angular y use yeoman desde la línea de comandos para crear una solución web mvc. Algunos lo vieron como "un paso atrás", que tenía que ser todo visual e integrado en Visual Studio.

Creo que con dotnet CLI se ha abierto un melón diferente, uno al que los programadores .net no estamos tan acostumbrados como los programadores node con npm, y es el uso de la línea de comandos. Esta ya no es cosa de devOps que hacen un script en powershell para hacer algo en Azure. Ahora podemos crear soluciones, agregar proyectos, descargar referencias, y aquellos comandos que ya conocíamos - como Add-migration y UpdateDatabase de Entity Framework - unirlos en un solo script.