There are already some posts on this topic of using Precompiled Razor Views, so I won’t duplicate that content.
Kam’s blog - Precompiled Views supported by Sitecore since Sitecore 8.2
Jeremy’s blog - possible side affect of Precompiled Views
Chris’s blog - Slow compilation when using MVC areas/Helix folder structure
Matt’s blog - ensuring your razor view paths are unique
And probably others, but these one’s stood out to me, and relevant for this post.
Read these articles first, I’ll wait.
So you’ve read the above articles, here’s a quick recap:
we know Precompiled Razor Views are supported by Sitecore since Sitecore 8.2.
We want to measure/benchmark before and after applying this performance fix, how else would you know it’s had the desired effect. And watch out for this Disk IO calls, which seem to be occurring even if have the Sitecore setting disabled “UsePhysicalViewsIfNewer” which seems counterintuitive.
If you are following a MVC areas/Helix style structure with multiple folders for your views, it looks like using precompiled razor view is going to be really beneficial in your case.
Ensure you are using unique MVC area/Helix folder names & unique razor file paths across projects to avoid issues, just like you would if they were physical files in one project.
Well first I want to draw attention to “UsePhysicalViewsIfNewer” setting.
Check in your Sitecore setup what this value is set to.
If for example you have received a Sitecore Support patch/hotfix with a new .cshtml file
E.g. Issue 214239 for “\sitecore\shell\client\Business Components Library\version 2\Layouts\Renderings\ListsAndGrids\Grid.cshtml”
Which includes a config patch which changes “UsePhysicalViewsIfNewer” to true to load the .cshtml file with the fix, rather than the precompiled view in the assembly.
Those disk IO calls which seem to occur either way (more on that later), are defiantly going to occur if you tell it to.
This also explains the guidance you might see where the .cshtml file last modified data must be more recent than the .dll file, otherwise it wouldn’t be loaded.
So possibly a Sitecore Support patch to a .cshtml file might undo some of the performance gains we are trying to achieve. As with everything measure.
If you don’t have “UsePhysicalViewsIfNewer” set to true, can skip this next section, and skip to the hotfix, otherwise read on.
Disclaimer, I’ve only tried this on a dev machine. And not completed benchmarking/testing
Maybe if you are only worried about the Sitecore MVC .cshtml hotfix for Content Authoring, and only want the compilation benefit on Content Delivery so could change this setting “UsePhysicalViewsIfNewer” to true just for Authoring?
However, if you want to have the compilation benefit on Content Authoring as well as the MVC .cshtml fix. One possible way could be to create a new project named “ZZZZZ…” with Razor compilation enabled and place the fixed .cshtml file in that project with the matching path of the file you want to override from Sitecore.
And add to the pre-compilation configuration a reference to this new assembly.
<configuration xmlns:patch"http://www.sitecore.net/xmlconfig/">
<sitecore>
<mvc>
<precompilation>
<assemblies>
<assemblyIdentity name="ZZZZZ......AssemblyName" />
</assemblies>
</precompilation>
</mvc>
</sitecore>
</configuration>
We are going to turn the bug from Matt’s blog - ensuring your razor view paths are unique into a solution.
“The problem becomes apparent when two assemblies have the same generated virtual view path, the assembly that comes alphabetically last wins out and overwrites the value corresponding to the virtual path key string in the _views dictionary.”
We are going to deliberately overwrite the Sitecore Pre-compiled view, with the fixed Pre-compiled view, but naming the assembly with the fixed .cshtml file with a name Alphabetically after the original Sitecore Assembly.
If this is a good solution without drawback, perhaps support could do this, to save us the time of doing it ourselves?
Or actually Sitecore could re-issue the original .dll with the fixed Razor view, so don’t need to overwrite it.
And now with the new Hotfix only model, they probably would do this.
Still this might be relevant for an existing patch you have, prior to the new Hotfix model.
With this technique, can leave “UsePhysicalViewsIfNewer” set to false, and override a Sitecore precompiled view.
More testing required to verify this works without drawback.
Disclaimer, I’ve only tried this on a dev machine. And not completed benchmarking/testing
Going back to Jeremy’s blog possible side affect of Precompiled Views. If look at the comments section, can see I enquired about if this was still an issue in Sitecore 9, and had a little more success from Sitecore Support who confirmed this was a bug in Sitecore and not the RazorGenerator project.
Looking at the contents of Sitecore.Support.192470.dll, can see it removes the first MVC view engine from the list, I asked Sitecore Support why and got this answer:
The setting UsePhysicalViewsIfNewer works as expected for all precompiled views except the ones that come from a couple of SPEAK dlls (Sitecore.Speak.Web.dll and Sitecore.Speak.Components.Web.dll). The UsePhysicalViewsIfNewer setting value is used to initialize PrecompiledViewAssembly objects which will be a part of the RazorGenerator.Mvc.CompositePrecompiledMvcEngine. Sitecore initializes an instance of Sitecore.Mvc.SitecoreRazorViewEngine derived from the CompositePrecompiledMvcEngine. And further the instantiated engine is encapsulated in the Sitecore.Mvc.InstrumentendViewEngine type.
So far so good.
The problem is that there is an extra PrecompiledMvcEngine instance that comes from SPEAK. This particular engine instance ignores the UsePhysicalViewsIfNewer setting. The engine instance gets placed at the very first position of the ViewEngines.Engines list. And the issue happens when this “incorrect” engine is taken via a FirstOrDefault LINQ func by Sitecore MVC. Please also notice that with the current architecture the only possible way to fix this is to remove the engine from the list.
This would seem to explain the issue Jeremy was having.
However I’ve yet to benchmark this solution, to see if solves the disk IO issue, but got a logical explanation from Sitecore Support.
I’m not sure if this is still an issue or fixed in later version of Sitecore after Sitecore 9. But a quick scan through the recent version release notes I can’t see either of the public reference numbers 192470 or 119596.
Disclaimer, I’ve only tried this on a dev machine. And not completed benchmarking/testing
If you are experiencing issues with Compiled Razor views and disk activity even with “UsePhysicalViewsIfNewer” set to false, perhaps check if this fix is applicable for the version of Sitecore you are on, and measure if it has the desired impact.
I’m thankful to receive my 1st Sitecore MVP award in the Technology category for 2020.
I’ve been using Sitecore since Sitecore 6 in 2011.
Keep sharing and trying if didn’t make it this year, this is my first year I’ve been fortunate enough to be selected for the MVP award after several years of applying.
Although it’s not enough to just keep on applying, you can’t get the award if you don’t apply, and you might get some feedback what you need to improve upon.
A lot of my activity with Sitecore might not be publicly visible, and probably explains why I’ve not received this award previously.
Digging out dotpeek, finding the root cause of an issue, and possibly supplying a fix on occasion to Sitecore support for review (of course would always prefer to use an official hotfix, but to prove have found the problem & working solution I might get there first).
Or again using dotpeek finding a way to add in support for a feature that isn’t currently supported, and sharing the approach with Sitecore to make it easier to extend in future upgrades, or be integrated into the product in the future.
This might not be visible to the community straight away, but hopefully makes the product better in the long run.
Now with the new single Hotfix model per version of Sitecore, these identified issues fixes are more likely to get into the product quicker, as well as making upgrades easier.
I’ve been trying to share what I’m up to, either blogging, asking/answering questions on Stack Exchange, or presenting when I can.
I’ve also been on a train the trainer course on .net core, Docker, K8s and AKS, and delivered this training.
As well as attended a course on improving my public speaking skills.
All of which has helped me practice my public speaking.
Special mentions to Sitecore User Group UK and Sitecore Discussion Club for letting me present.
And Steve McGill and Martin Miles for running them.
As well as to the Sitecore Support & Product teams for collaborating on tickets, and working on getting the fixes/enhancements into the product.
Plus of course the awesome Sitecore community, whether that’s Twitter, Sitecore Slack, Blogs, Sitecore StackExchange, SCUG Meetups & Sitecore Discussion Club, SUGCON, Symposium etc.
As well as the awesome team I work with, but as this is my personal blog I’ll leave it at that.
Thanks for reading my blog, more to follow!
Back in February this year I gave a presentation at the London Sitecore User Group “Improving the Solr Content Search Provider”.
My first talk at a Sitecore User group.
Although I regularly attend the Sitecore discussion club, and have presented there on several occasions.
At the presentation I included a link to a github repository with a list of known issues and their public reference numbers.
The list of issues will vary between Sitecore versions, I’ve included the list of issues I’ve come across between Sitecore 8.2 up to Sitecore 9.0 update 2.
Including:
The github repostiory also included an example implementation of patterns to address some of the fallacies of distributed computing.
Related blog posts:
On reasons not to use each of them, at least on Content Delivery, or when querying over lots of items.
Changing MyItems & Unlock all to use Solr, rather than a Sitecore Query.
I told you Sitecore.Query was slow, and Memory Intensive.
Infact since giving this talk, one of the issues that got me to customise the Sitecore Solr Search provider in the first place reared its head again. Sitecore not being able to startup when Solr is down.
Well the number of Sitecore indexes had grown over time.
On startup each index was doing it’s own check to see if Solr was available, and waiting for a timeout/exception. This was happening in series. Depending on the type of error you get, if it’s a timeout, this can result in Sitecore taking longer to startup than IIS allows. Causing IIS to recycle the application and try again, in an infinite loop. Oh dear!
So I’ve added to the github repository a new issue 314454 - Sitecore doesn’t startup when Solr Down.
You can simulate on your local PC latency to Solr using Fiddler. If you change your solr connection string to
http://localhost.:8983/solr;solrCloud=true
Notice the “.”, will ensure the traffic goes through Fiddler
Change your Sitecore IIS Application Pool to run as your local user, as Fiddler automatically picks up traffic running as your local user. (Or you can change the proxy settings)
Then run Fiddler.
Under “AutoResponder” tab, you can add a Rule for requests matching
http://localhost.8983/solr/.....
The URL you set could be specific to a particular index, or request, depending on what you want to test.
Then on the response for that URL you can set
*delay:10000
with how many milliseconds you want to delay the request with.
Using this technique you can simulate a network timeout, rather than a quicker port not listening/service not running error.
And from this can replicate the issue of Sitecore note being able to start up, if you have enough indexes which all timeout on startup.
Sitecore doesn’t issue patches anymore, so instead you get a hotfix, which include all of the issue fixes for that version of Sitecore you are on.
For Sitecore 9.0 update 2, this was included in hotfix 323662-1.
And included changes to dlls
There were so many changes it felt like a mini Sitecore Upgrade. And the contract changed, had to rewrite our customisations for them to continue to work.
This hotfix fixes the slow startup issue, but only checking once if Solr is available, rather than per index. So make Sitecore much faster to startup when Solr is down.
There was also some work to make the initialising of the indexes to work in parallel, to further speed up the time for initialisation.
Each time we upgrade, we have to see if our customisations are still possible. Often the extension points/hooks we have used have gone, and we have to find new ones.
Even on this update to the hotfix which address 314454, we had to do a lot of rework.
Hopefully in a future version of the product the extensions points we require will be included in the product, and we won’t have to get out dotpeek to find a place to override, and use reflection/so many custom classes and overrides to change the behaviour to what we need.
As the hotfix isn’t publicly available in the nuget feeds, and the contract has changed.
I can’t update the example code to reference the hotfix, and for it to still compile.
If anyone is interested to see the examples updated to use the hotfix, reach out to me on twitter, and I can see about creating a feature branch.
Otherwise, I’m going to wait for a version of Sitecore which includes these fixes/contract changes, which is available in the nuget feed so I can update the examples and still have it compiling.