Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 24 de octubre de 2017
ASP.NET Core MVC Pues os voy a contar una historia que me ocurrió más de una vez al comenzar a utilizar ASP.NET Core 2. Y como supongo que no seré el único, creo que puede ser interesante compartirla por aquí para evitar pérdidas de tiempo innecesarias al resto de la humanidad ;)

Resulta que varias veces he publicado un proyecto ASP.NET Core y, tras finalizar y probar un poco la aplicación, he visto que me había dejado por detrás alguna chorradilla en una vista que tenía que corregir rápidamente. En lugar de volver a publicar el proyecto completo, cuando me ocurre esto suelo a retocar la vista y actualizar sólo ese archivo en el servidor, por ejemplo desde el menú contextual del archivo en Visual Studio:



Pero en este caso, una vez finalizó la subida del archivo al servidor, pulsé F5 en el navegador para comprobar que ya estaba todo correcto y… ¡vaya, todo seguía igual que antes! No pasa nada, pensé que no había publicado bien, por lo que volví a repetir el proceso y pocos segundos después pude comprobar que los cambios seguían sin ser aplicados en el servidor. ¿Qué podía estar ocurriendo?

Ah, claro, ¡el caché! La vista era retornada por una acción MVC decorada con el filtro ResponseCache, por lo que podría ser normal que continuara llegando al navegador la versión anterior. Eliminé caché, incluso probé desde otro navegador y ¡todo seguía igual que antes!

Ya lo único que se me ocurría es que la publicación hubiera fallado por algún siniestro bug de Visual Studio que no dejara rastro en las trazas, así que decidí ignorar al intermediario. Fui directamente al servidor para editar manualmente el archivo de la vista y… maldición, ¡no la encuentro! :-/

¿Qué está ocurriendo aquí?

Precompilación de vistas en ASP.NET Core

Pues sí, la bombilla se enciende en el momento en que por fin recuerdo de que mi aplicación está basada en ASP.NET Core 2. Todos los proyectos creados a partir de esta versión están configurados por defecto para compilar las vistas durante el proceso de publicación en un ensamblado con el nombre <App>.PrecompiledViews.dll. Esto podemos verlo fácilmente si ojeamos el directorio con los archivos de publicación:



Dado que este ensamblado contiene las vistas compiladas, observad que la carpeta Views no ha sido incluida entre los archivos que se despliegan al servidor, pues obviamente los .cshtml no son ya necesarios.

El hecho de precompilar las vistas es, en general, una buena idea. En primer lugar, porque antes de generar el paquete de publicación y enviarlo al servidor podremos detectar si las vistas contienen errores de compilación, lo que evitará que exploten más adelante en runtime.

La siguiente salida de consola muestra el error producido al publicar el proyecto habiendo introducido en la vista index.cshtml la expresión Razor "@Hello", siendo "Hello" una variable inexistente:
C:\MyMvcApp>dotnet publish -o publish
Microsoft (R) Build Engine versión 15.4.8.50001 para .NET Core
Copyright (C) Microsoft Corporation. Todos los derechos reservados.

  MyMvcApp -> C:\MyMvcApp\bin\Debug\netcoreapp2.0\MyMvcApp.dll
C:\MyMvcApp\Views\Home\Index.cshtml(5,7): error CS0103: The name 'Hello' does not exist 
in the current context [C:\MyMvcApp\MyMvcApp.csproj]

C:\ProgramFiles\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.mvc.razor.
viewcompilation\2.0.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.ViewCompilation.
targets(60,5): error MSB3073: El comando ""C:\Program Files\dotnet\dotnet.exe" 
exec --runtimeconfig "C:\MyMvcApp\bin\Debug\netcoreapp2.0\MyMvcApp.runtimeconfig.json" 
--depsfile "C:\MyMvcApp\bin\Debug\netcoreapp2.0\MyMvcApp.deps.json" 
"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.mvc.razor.
viewcompilation\2.0.0\build\netstandard2.0\Microsoft.AspNetCore.Mvc.Razor.
ViewCompilation.dll" @"obj\Debug\netcoreapp2.0\microsoft.aspnetcore.mvc.razor.
viewcompilation.rsp"" salió con el código 1. [C:\MyMvcApp\MyMvcApp.csproj]

C:\MyMvcApp>_
En segundo lugar, porque la aplicación ganará en velocidad de ejecución, pues las vistas no habrán de ser compiladas al ser accedidas por primera vez. Esto no es ninguna tontería, pues en muchas ocasiones este tiempo inicial no es aceptable para los usuarios. De hecho, he visto bastantes desarrolladores aplicando soluciones extravagantes tras el despliegue de una aplicación para asegurar que todas las vistas estén compiladas antes de que los usuarios entren al sistema.

A cambio perderemos la flexibilidad de poder hacer cambios directamente en producción y que éstos se recompilen automáticamente. A partir de este momento, cualquier cambio en una vista deberá ir seguida de una nueva publicación de la solución para actualizar los ensamblados en el servidor.

Pero, ¿y si no quiero precompilar?

Como hemos comentado, la precompilación de vistas está incluida por defecto en proyectos ASP.NET Core MVC, a partir de su versión 2.0. Sin embargo, si por cualquier motivo preferimos que las vistas no sean precompiladas, podemos desactivar esta opción retocando ligeramente el archivo de proyecto .csproj para establecer a falso el switch <MvcRazorCompileOnPublish>:
<Project Sdk="Microsoft.NET.Sdk.Web">  
    <PropertyGroup>
        <TargetFramework>netcoreapp2.0</TargetFramework>
        <MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
    </PropertyGroup>
    ...
</Project>    
Configurando el proyecto web de esta forma, si publicamos el proyecto podremos ver que la carpeta Views ha vuelto a incluirse en el paquete, y que han desaparecido los archivos resultantes de la compilación de vistas:



Publicado en Variable not found.

5 Comentarios:

Michel dijo...

Muy buena data!!..
La verdad aun no me meti en el mundo Core de ASP.Net, ya que me parece que aun, no esta bien metida en el mercado. Pero es algo que obviamente, se viene y es interesante.

Joseba dijo...

Una explicaccón cristalina pero me queda alguna dudilla.

He entendido que si quiero ganar velocidad en la publicación debo perder velocidad en la ejecución.

Una vez se ejecuta la aplicación la primera vez ¿se precompilan las vistas y aparece ese ficherito PrecfompiledViews.dll y volvemos al punto inicial de que no vuelve a compilar la vista si la publico sola?

Saludos.

José María Aguilar dijo...

Hola!

@joseba, el precompiledviews.dll se genera en tu equipo, en el momento de publicar. Si has subido sin hacerlo, no existirá; se compilarán como siempre, en tiempo de ejecución conforme se van solicitando.

Saludos!

Joseba dijo...


Pero entonces una vez ya esté compilado si publico solo la vista ésta no se actualizará, ¿no?

José María Aguilar dijo...


Hola!

Si publicaste con las vistas precompiladas, la carpeta /Views ni siquiera existirá en tu servidor. Si subieras al servidor una vista modificada a esa carpeta sería ignorada, pues se toman desde ese ensamblado.

Si publicas de nuevo, aunque sólo hayas actualizado una vista, volverás a generar el ensamblado precompiledviews.dll completo.

Saludos!