16

I have a Windows Azure web role that contains a web site using ASP.NET MVC. When an HTTP request arrives and a page is first loaded the view (.aspx or .cshtml) is compiled and that takes some time and so the first time a page is served it takes notable longer than later serving the same page.

I've enabled <MvcBuildViews> (described in this answer) to enforce compile-time validation of views, but that doesn't seem to have any effect on their compilation when the site is deployed and running.

Azure web roles have so-called startup tasks and also a special OnStart() method where I can place whatever warmup code, so once I know what to do adding that into the role is not a problem.

Is there a way to force compilation of all views?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979

5 Answers5

15

Take a look at Precompiled Razor Views by David Ebbo

Why would you want to do that?

One reason to do this is to avoid any runtime hit when your site starts, since there is nothing left to compile at runtime. This can be significant in sites with many views.

Also, you no longer need to deploy the cshtml files at all, resulting in a smaller deployment file set.

Another cool benefit is that it gives you the ability to unit test your views, which has always been something very difficult with the standard runtime compilation model. I’ll cover that in more details in a future post.

archil
  • 39,013
  • 7
  • 65
  • 82
8

Turns out there's ASP.NET Precompilation that can be performed using ClientBuildManager.PrecompileApplication and mimics the on-demand compilation behavior, but just compiles every page. Tried it - the first load looks notably faster.

The non-trivial part is what to pass as ClientBuildManager constructor parameters. The solution is to enumerate all .Applications of the Site object and for each item in .Applications enumerate all .VirtualDirectories and use Path and VirtualPath from each item as parameters to ClientBuildManager constructor.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • What strings do you provider as parameters when creating `ClientBuildManager` class? – trailmax Feb 25 '14 at 17:12
  • 1
    @trailmax: I get the `VirtualDirectory` object of the application and from that I get `Path` which goes as the first parameter and `PhysicalPath` that goes as the second parameter. – sharptooth Feb 26 '14 at 07:30
3

Is this an initial-load issue or a steady-state issue? One issue seen is that of app pool recycling, which defaults to 20 minute timeout. If you disable timeout (or set it to something large), is that a valid workaround?

Here's another SO answer discussing AppPool timeout and how to disable it. Basically:

%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00
Community
  • 1
  • 1
David Makogon
  • 69,407
  • 21
  • 141
  • 189
  • This is another problem of which I had no idea. Thanks a lot. However I'm asking about compiling the ASP.NET views into executable code and that still has to be done regardless of whether apppool is recycled. Do you have any idea of why there's a recycle in the first place? I mean I deploy a web role to have a web site at all times. Why is it recycled? – sharptooth May 16 '12 at 14:01
  • The AppPool recycle is the same as Windows Server AppPool recycle. I've seen arguments for changing this for Windows Azure, but then there'd be an inconsistency between Windows Server on-prem and in Windows Azure, and the goal is to keep things consistent. In a high-traffic scenario, you'd probably not hit the recycle issue. Easy enough to adjust with the code above, and works the same, whether on-prem or in cloud. – David Makogon May 16 '12 at 14:23
1

Add this to OnStart:

  using (var serverManager = new ServerManager())
        {
            string siteName = RoleEnvironment.CurrentRoleInstance.Id + "_" + "Web";
            var siteId = serverManager.Sites[siteName].Id;
            var appVirtualDir = $"/LM/W3SVC/{siteId}/ROOT";  // Do not end this with a trailing /

            var clientBuildManager = new ClientBuildManager(appVirtualDir, null, null,
                                        new ClientBuildManagerParameter
                                        {
                                            PrecompilationFlags = PrecompilationFlags.Default,
                                        });

            clientBuildManager.PrecompileApplication();
        }
Mister Cook
  • 1,552
  • 1
  • 13
  • 26
0

If you use the Publish functionnality of Visual Studio, there is a much simpler option :

On the Publish dialog > Settings pane, expand File Publish Options and check Precompile during publishing then click configure. On the Advanced Precompile Settings dialog box, uncheck Allow precompiled site to be updatable.

source: https://msdn.microsoft.com/en-us/library/hh475319.aspx

Mik
  • 1,306
  • 1
  • 10
  • 14