ASP.NET MVC: Precompiling views
This blog post is about how to really precompile ASP.NET MVC views. It destroys the myth about MvcBuildViews as precompilation tool and shows you how to configure precompiling. It also stops on some internals of precompiling and explains what are the options and limitations with it. There is also real-life example for Azure where precompiling of views may avoid some serious headaches that one may face otherwise.
What is MvcBuildViews?
MvcBuildViews is often mistakenly considered as something that when activated results in precompiled views. It doesn’t, actually. It is just a thing to include views to build process but it doesn’t compile these to project binaries folder. MvcBuildViews builds views temporarily and gives build results back to building process. If there were errors then build fails and errors are shown in Visual Studio errors window.
You can find out more about MvcBuildViews from Jim Lamb blog post Turn on Compile-time View Checking for ASP.NET MVC Projects in TFS Build 2010.
How to precompile views?
As precompiling is kind of expensive and time consuming process you really want to do it when publishing application to test or live environment. Simplest way to do it is using web site publishing. Publishing configuration has settings page where you can turn on compiling of views.
If you publish your web application then you will discover that only global.asax has something precompiled for it. But there is nothing for views.
By default it is expected that there can be updates to views and it is possible only if views are not compiled to assembly. As soon as there is assembly for views modifications to view files are not automatically reflected in application output.
Let’s open advanced settings and turn off updates to views. As ASP.NET compiler creates separate assembly for every view it’s possible we get big number of very small assemblies if there are many views. It’s possible to specify the name of assembly where all those small view assemblies are merged.
Now you are good to go with precompiled views when publishing your application.
NB! Although it may seem like good idea to have precompiled views available also on dev boxes, I suggest you to abandon this idea. Precompiling takes time more than developers want to wait and it slows down their progress as after every build they must wait until precompiling is done.
NB! If you precompile views then views are not updatable anymore. It means that if you change view file on server you don’t see any changes in output. This is because precompiled views are called from DLL-file. You have to publish your application again if you made changes to views.
Precompiled views after publishing
After publishing precompiled views can be found from bin folder of web application. In my case there is AppCode.dll file that contains code for all precompiled views. But besides this there are also files with .compiled extension. These files tell ASP.NET where is output of given view.
In my case there’s file _smsdialog.cshtml.49841770.compiled in bin folder. Here is the content of this file.
<preserve resultType=“2“ virtualPath=“/Views/Dialogs/_SmsDialog.cshtml“
hash=“ffffffffda035ab6“ filehash=“166a10c1bc59“ flags=“110000“
assembly=“AppCode“ type=“ASP._Page_Views_Dialogs__SmsDialog_cshtml“>
<filedeps>
<filedep name=“/Views/Dialogs/_SmsDialog.cshtml“ />
</filedeps>
</preserve>
It defines file dependency and specifies where is the code for this view (assembly and type attributes of preserve node).
If I open AppCode.dll with decompiler I can see the source code of precompiled view.
As precompiling is done by ASP.NET command-line utilities you can also use precompiling on your build server.
Precompiled views on Azure
I worked on application that has some complex views. Compiling this views on runtime is slow even on dev box wit fast hard disc. It turned out to be times slower on Azure compute instance where web application is hosted. I investigated virtual machine that runs compute role and made the following discoveries:
- regular discs on Azure are very slow,
- compared to similar discs available they beat them only with one thing: the energy consumption,
- SSD-s are way more expensive on Azure that regular discs,
- the less disc I/O application generated the faster it is.
This is ideal case for precompiling the views. It’s not possible to avoid those .compiled files but getting all code for views to one assembly makes application startup faster because there’s only one library to load. With precompiled views your application works way faster after deployment because ASP.NET doesn’t have to build and compile views to compute role hard disc.
Wrapping up
The main take-away of this post is: MvcBuildViews is here to make building of views as part of web application building process. It doesn’t generate any output to binaries folder. Views are precompiled during publishing process and precompiling happens only if views are not expected to be modified. It is possible to configure how precompilation is done. This way it is possible to merge binaries of precompiled views to one assembly. This way it is possible to shorten the time it takes for application to start. As it turns out then precompiled views are good choice for web applications that run on Azure as it avoids some really slow disc I/O and web application gets highly responsive way faster than otherwise.
Informative. Dispelled a lot of myths about pre-compilation. Do yiu have any tips for improving the peofdmance of the aspnet_compiler during publishing. In my project this step takes almost 1 hour and it’s not uncommon from what I understand.
I suggest you to check you dev box disc performance. Visual Studio and ASP.NET web tools may cause massive disc I/O when building, compiling or generating things. If disc is the bottle neck then switch over to SSD.
Have you every encounter a failure on Azure with precompiled views?
It worked on the dev machine but when deployed on the azure server it would not run.
I had but could not solve it and went back to deployment without precompiled views …
// Ryan
> As precompiling is done by ASP.NET command-line utilities you can also use precompiling on your build server.
Do you have examples of those command line utilities?
When I try your steps I get some failures because the post-compiler does not recognize C# 6 features (specifically string interpolation).
Thanks for the post, this is something I’ve been wanting to nail down for a long time!
*Update* on the C# 6 syntax not recognized error: I changed my web.config to “Content” Build Action (previously it was None) and in doing so, the web.config file was copied to the `obj\Release\AspnetCompileMerge\Source` directory. Now the C# 6 syntax is recognized.
It is worth noting that I have the following tag changes from this stackoverflow answer: http://stackoverflow.com/questions/31548699/how-to-use-c-sharp-6-with-web-site-project-type#answer-31548773
Ryan, I have used precompiled views only on compute instances as most of my Azure customers use these due to need for more control over VM-s where applications run. With compute instances we have had no problems this far.
Thanks for this great post.
Any chance you call tell me how to precompile views via msbuild? You mention the commandline tools. I’m using Team Services for building and deploying the application. So I’m hoping for something a little easier.
Maybe I’ll have to switch to ‘web deploy’ in the Azure RM step. And set some parameters that way. I already used Visual Studio to create a pubxml file. Will probably look into that tomorrow. https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/AzureRmWebAppDeployment/README.md
I found the solution. Can be done with msbuild parameters, nothing special. Wrote a blog post about it and added a callback to this post. Thanks again for pointing me in the right direction.
http://blog.deltacode.be/2017/01/08/fix-slow-startup-of-asp-net-mvc-5-on-azure-app-services/
You mentioned precompile views in Azure but you didn’t explain how. This cannot be done using the standard publishing tool under Visual Studio.
Firas, it is standard publish dialog of Visual Studio and view compilation settings apply no matter where you publish your application – be it Azure or some other target environment like file system.
On Azure we really need it because just in time compilation of views can be very slow due to slow disks that are cheaper than SSD-s.
Thanks Gunnar. This option is not supported if you are deploying ASP.NET MVC project to web role. I read a lot about it and eventually the tool doesn’t support it.
If this is something you believe it exists there, I would appreciate it if you can share with me the steps to do it.
If VS deploys web role different from what regular web application publishing does then you can use dirty trick like described here: http://gunnarpeipman.com/2011/12/deploying-independent-web-applications-to-windows-azure-using-single-web-role/ This way you get all files to package that are created during usual web application publishing.
Actually the compiling of views is command that is given to MSBuild during publishing. You can also write DOS or PowerShell script for site deployment and call MSBuild there with correct parameters.
Publishing with built views works also well for Azure app services (previous web sites service). I can confirm it.
This is a great article. So simple and a MASSIVE increase in performance of my Azure hosted Web site. Prior to this I was seriously thinking of moving to a different platfrom.
Building of views is slow and if it happens in server then also the first request is very slow. In case of Azure web sites consider also slow disks that are okay for web because once application is loaded it doesn’t make any remarkable disk I/O.
This was very helpful! Thank you for maintaining this content.
Hi Gunnar, thanks for the article, although i am having error on some views on production as below,
“`
[C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\01f1f200\5c2c0506\assembly\dl3\70447e16\5907a98d_8289d501\AppCode.dll] No string associated with token.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.BadImageFormatException: [C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\01f1f200\5c2c0506\assembly\dl3\70447e16\5907a98d_8289d501\AppCode.dll] No string associated with token.“`
Can you please help out if possible, what could be the issue?
Thanks for your time.
Hi Gunnar, thanks for the article, although i am having error on some views on production as below,
“`
[C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\01f1f200\5c2c0506\assembly\dl3\70447e16\5907a98d_8289d501\AppCode.dll] No string associated with token.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.BadImageFormatException: [C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\01f1f200\5c2c0506\assembly\dl3\70447e16\5907a98d_8289d501\AppCode.dll] No string associated with token.“`
Can you please help out if possible, what could be the issue?
Thanks for your time.
Pingback:How to make ASP.NET Core compile modified views
Hi,
Is there a way that we could get back view file(cshtml) from dll. I could see cs file being generated by decompiler (dotPeek) but not cshtml.
Any suggestion ??
Hi,
AFAIK there are no tools to restore CSHTML once it is compiled to DLL.
Hi, thanks for this article. I use precompiled views on Azure Web Apps and it’s much faster and I do not have to warmup my app like before – a real pain.
What I’m trying to do now is have dynamic views for client customization and I do not want to add all those custom views into my project. We decided to put the view code into the database and when we need to render it we copy it to disk in a special folder as a cshtml file and we refer to it. Only problem is that it will not compile the view as it expects all views to be precompiled…
Any clue on how I can force a dynamic compilation of a view in that case?
thanks
I have to admin I have never worked on such a mixed scenario. Sorry.
Hi, I’m using the precompiled settings as described in your post. In order to test that my application is actually reading the compiled views, I renamed one of the .cshtml files and expected the application to still function normal, which it did. However, when I deployed to the server and also performed a rename of one of the .cshtml files, the application was actually looking for that specific view, and was not reading from the compiled views. Do you know why? Is there anything that I am missing? Is there a difference between the local published application and the deployed application wrt the compiled views?