How to view Razor changes without building the project. There is no need to build the project to see changes in Views.

When I was a junior developer I remember my team lead telling me:

No, you don’t need to rebuild the solution if you modify something views

I’ve absorbed this phrase and kept telling it to my students. Until recently to realize that is not of actuality anymore. For many years after that, I stopped working in ASP MVC projects, having only APIS, angular, and React client apps.

Recently I’ve upgraded an MVC project from 2.2 to 3.1 and needed to make some changes in Views.

Nothing bad so far, I still remembered how it’s done. Yey! It is like riding a bike.
Oddly enough, I had to rebuild the solution to see the changes made in Views and I was really annoyed, I had just static HTML and couldn’t understand why I have to rebuild. Up until this moment, compilation of views was triggered by the editing. I started to dig around and did some research, and here’s what I’ve found out.

Razor compilation is enabled by default only for build/publish

Razor compilation is enabled by default only for the build and publish scenarios, not for runtime aka when you edit the view.

Now, if you want that functionality back, you need to install a NuGet package: Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation  and add the middleware and boom, it works.

services.AddControllersWithViews()
        .AddRazorRuntimeCompilation();

Conditional runtime compilation

Another method to obtain the same thing, which I really don’t like is based on directives. This way, you can keep the default mode, but enable what you need only when you are debugging (running locally).

First, you need to start by editing your csproj file to add a condition on the package.


<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" 
Version="3.1.3" Condition="'$(Configuration)' == 'Debug'" />  

After that, you need to make some adjustments in your startup file to add the condition. Start by adding a property to hold IWebHostEnvironment, and set the value from the controller.

  public Startup(IConfiguration configuration, IWebHostEnvironment env)
        {
            Configuration = configuration;
            HostEnvironment = env;
        }

        public IConfiguration Configuration { get; set; }

        public IWebHostEnvironment HostEnvironment { get; }

After you did that you need to add the #if condition to enable the ‘dynamic’ loading for the conditional runtime compilation

            var builder = services.AddControllersWithViews();
#if DEBUG
            if (HostEnvironment.IsDevelopment())
            {
                builder.AddRazorRuntimeCompilation();
            }
#endif

With this in mind, make sure you change the IWebHostEnviroment scattered around your Startup class, and point it to the newly introduced property. Is not the cleanest solution, I do not prefer this, but it does the job. More than that, we all lie to ourselves that, ok, I’m gonna change the default, and just comment the line of code before deploying. Only this will never happen.

In the official docs, they say that by using the conditional compilation you make sure that the published output uses the compiled views, are smaller in size, and it doesn’t enable file watchers in production. All these might be true, but it doesn’t make my developer experience nicer. What do you think?