Synthesis Object Mapping Performance

This morning I saw a post on the performance of the Glass Mapper by Konstantin Cherkasov and thought I’d run a quick test of Synthesis in a similar situation. In Konstantin’s testing, he found a GlassCast + field access to be nearly 2,000 times slower than using the Sitecore API to access the same field value.

I decided to read the entire contents of the web db, then convert it all to Synthesis items and read the display name field, since they’d all have that. In my case, that worked out to 5148 items - less than Konstantin’s test with 20,000 but it was what was handy. Note that with Synthesis, AsStronglyTypedCollectionOf() returns a collection of IStandardTemplateItem. This doesn’t mean it’s not doing any fancy mapping, however - this is just the base interface for all items. Individual collection items are still mapped to the appropriate template class; e.g. for an Article, you could do if(collectionItem is IArticleItem) and it would be true.

This gist shows the code I used, and average results. Synthesis was about 3x slower than the native Sitecore APIs (native: 16-20ms, Synthesis: 54-60ms, sample size 5148 items); still suboptimal, but a heck of a lot less than 2000x.

The difference is probably mostly due to the fact that Synthesis is a wrapper (internally it reads from an Item) instead of a mapper (full POCOs/proxies), so it can be a lot lazier about loading values.

Enabling Async in Sitecore Controller Renderings

IMPORTANT NOTE:

The information in this post unfortunately does NOT work for controller renderings as I had originally thought. It does, however enable you to use async actions outside of Sitecore contexts (e.g. in directly invoked controllers via non-Sitecore routes or Html.RenderAction() on a Sitecore rendering)

For the past few years, the rest of the .NET world outside Sitecore has been adopting the new async/await programming model that was introduced in .NET 4.5. This model essentially allows you to free up your worker thread while you’re waiting for something else to happen to continue exection. WTF does that mean?

Ok, so imagine you have a very simple web server that has 20 execution threads. This more or less means you can process 20 HTTP requests at the same time before you have to start queuing incoming requests - which kills performance.

Now suppose you’re making an expensive database call that takes 5 seconds on each request, and you get 40 requests at once. Without async, you have no choice but to send 20 requests into the queue. But with async, you can await the expensive database call - which frees up your execution thread(s) for someone else to use for actual processing while you wait for the database. So with an async database call and your 40 requests, you’d start processing 20 requests and rapidly start awaiting the database. This would enable the web server to start processing the other 20 queued requests instead of taking up execution threads that are doing nothing but wait! Then imagine if the latter 20 requests needed CPU time instead of database time - the web server CPUs would remain much more loaded over time and get more work done using the same resources.

Sounds good, right? But one of the down-sides of async is that you really need async calls from top to bottom to avoid deadlocks in ASP.NET. In other words, you could write your SQL API or REST client using async APIs all day - but unless the controller you invoke the APIs from is ALSO async, you’ll either get a deadlock or very little performance improvement. Unfortunately, Sitecore (as of 8.0 Update-2 anyway) does not support async controller actions. I didn’t like this, so I set out to fix that.

Ironically, the problem was very simple and rather hilarious. Sitecore MVC uses its own ControllerFactory which essentially wraps the default IControllerFactory from ASP.NET MVC and decorates it with some Sitecore-specific stuff. One of the things it does is look for the IActionInvoker on each controller, and if one exists wraps that implementation similarly with SitecoreActionInvoker to alter the way controller actions are invoked.

Looking around in the ASP.NET MVC source code, you can see that there are two interfaces for action invokers: IActionInvoker and IAsyncActionInvoker. Guess what? Sitecore’s ActionInvoker implements IActionInvoker but NOT IAsyncActionInvoker - which means that even though the default MVC action invoker it was wrapping supported async invocation, the wrapper’s lack of IAsyncActionInvoker implementation meant ASP.NET MVC wouldn’t use async invocation at all - and would instead throw an error that you cannot return a Task<ActionResult> from a synchronous controller. What?!

It’s a simple matter to patch Sitecore’s ControllerFactory, which is registered in the <initialize> pipeline:

<initialize>
    <processor type="Foo.Pipelines.Initialize.InitializeAsyncControllerFactory, Foo.Core" patch:instead="*[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']"/>
</initialize>

using Sitecore.Mvc.Controllers;
using Sitecore.Mvc.Pipelines.Loader;
using Sitecore.Pipelines;
using ControllerBuilder = System.Web.Mvc.ControllerBuilder;

The class to override the controller factory:

namespace Foo.Pipelines.Initialize
{
    /// <summary>
    /// Replaces the standard Sitecore MVC controller factory with one that knows how to do async action invocation.
    /// </summary>
    public class InitializeAsyncControllerFactory : InitializeControllerFactory
    {
        protected override void SetControllerFactory(PipelineArgs args)
        {
            SitecoreControllerFactory controllerFactory = new SitecoreAsyncControllerFactory(ControllerBuilder.Current.GetControllerFactory());
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
        }
    }
}

Then override the way the SitecoreControllerFactory patches the IActionInvoker on the controllers:

using System.Web.Mvc;
using System.Web.Mvc.Async;
using Sitecore.Mvc.Configuration;
using Sitecore.Mvc.Controllers;

namespace Foo
{
    /// <summary>
    /// Patches the normal Sitecore controller factory to enable executing async actions and using async/await
    /// The ActionInvoker that Sitecore MVC wraps the inner action invoker with does not implement IAsyncActionInvoker,
    /// which means ASP.NET MVC does not try to execute it async if needed, and precludes async/await.
    /// </summary>
    public class SitecoreAsyncControllerFactory : SitecoreControllerFactory
    {
        public SitecoreAsyncControllerFactory(IControllerFactory innerFactory) : base(innerFactory)
        {
        }

        protected override void PrepareController(IController controller, string controllerName)
        {
            if (!MvcSettings.DetailedErrorOnMissingAction)
            {
                return;
            }
            Controller controller2 = controller as Controller;
            if (controller2 == null)
            {
                return;
            }

            /* BEGIN PATCH FOR ASYNC INVOCATION (the rest of this method is stock) */
            IAsyncActionInvoker asyncInvoker = controller2.ActionInvoker as IAsyncActionInvoker;

            if (asyncInvoker != null)
            {
                controller2.ActionInvoker = new SitecoreAsyncActionInvoker(asyncInvoker, controllerName);
                return;
            }
            /* END PATCH FOR ASYNC INVOCATION */

            IActionInvoker actionInvoker = controller2.ActionInvoker;
            if (actionInvoker == null)
            {
                return;
            }
            controller2.ActionInvoker = new SitecoreActionInvoker(actionInvoker, controllerName);
        }
    }
}

And finally, implement an override of SitecoreActionInvoker which implements IAsyncActionInvoker:

using System;
using System.Web.Mvc;
using System.Web.Mvc.Async;
using Sitecore.Mvc.Controllers;

namespace Foo
{
    /// <summary>
    /// Literally all this does is provider an IAsyncActionInvoker wrapper the same way SitecoreActionInvoker wraps non-IAsyncActionInvokers
    /// This instructs ASP.NET MVC to perform async invocation for controller actions.
    /// </summary>
    public class SitecoreAsyncActionInvoker : SitecoreActionInvoker, IAsyncActionInvoker
    {
        private readonly IAsyncActionInvoker _innerInvoker;

        public SitecoreAsyncActionInvoker(IAsyncActionInvoker innerInvoker, string controllerName) : base(innerInvoker, controllerName)
        {
            _innerInvoker = innerInvoker;
        }

        public IAsyncResult BeginInvokeAction(ControllerContext controllerContext, string actionName, AsyncCallback callback, object state)
        {
            return _innerInvoker.BeginInvokeAction(controllerContext, actionName, callback, state);
        }

        public bool EndInvokeAction(IAsyncResult asyncResult)
        {
            return _innerInvoker.EndInvokeAction(asyncResult);
        }
    }
}

Then you can go forth and write lovely async controller renderings!

public async Task<ActionResult> AsyncActionMethod()
{
    // download a bunch of URLs in parallel with await
    var webClient = new WebClient();

    var urls = new[] {
        "https://google.com",
        "https://bing.com",
        "https://yahoo.com"
    }.Select(url => webClient.DownloadStringTaskAsync(url));

    var contents = await Task.WhenAll(urls);

    // or just await one task
    var google = await webClient.DownloadStringTaskAsync("https://google.com");

    // execution will pick up right here when all the awaited tasks are done - thawing the thread to finish execution

    return View(contents);
}

Have fun!

Extending Sitecore Rich Text Preview CSS

The other Sitecore Kam wrote an excellent post titled User Specific or Multi Site Specific CSS styles in Sitecore Rich Text Editor a few months ago. I noticed one gap in what it did, however: changing the RTE configuration does not change the preview of the rich text shown in the Sitecore content editor interface.

This means that you’d see the site specific styles when in the RTE proper, but not when browsing the item in the content editor.

So here’s how to accomplish just that. The RTE preview is rendered by the sitecore/shell/Controls/Rich Text Editor/Preview.aspx page. Being a normal Web Form page, we can hack its Inherits attribute to something else in order to inject our custom CSS:

<%@ Page ... Inherits="MyLibrary.MultisiteRichTextEditorPreview, MyLibraryAssembly" %>

Then we have to create a class which inherits the default codebehind class, Sitecore.Shell.Controls.RADEditor.Preview:

using System;
using System.Web.UI;
using Sitecore.Shell.Controls.RADEditor;

namespace MyLibrary
{
    public class MultisiteRichTextEditorPreview : Preview
    {
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            // replace the method call here with whatever you're using to resolve a custom RTE CSS path(s)
            // note that the query string parameter 'id' is the context item ID here just like in the EditorConfiguration Kamruz blogged about.
            var stylesheetPath = MultisiteRichTextEditorUtility.GetRichTextEditorCssPath();

            if (stylesheetPath != null) Stylesheets.Controls.Add(new LiteralControl(string.Format("<link href=\"{0}\" rel=\"stylesheet\">", stylesheetPath)));
        }
    }
}

Finally, we need to ‘improve’ our RTE stylesheet (this is optional, but excellent!):

* {
    font-family: "Comic Sans MS" !important;
    color: pink !important;
}

And then we have our newly enhanced rich text preview:

A Multiple Root Treelist Field

Recently I came across a need to allow selecting items for a TreeList field from several locations - specifically, we needed to be able to choose images OR videos to assign, and those were in different places in the content tree.

This has been done before, but there was altogether too much copied private method in that solution for my taste - and that it appears to not work with Sitecore 7.5 sealed the deal. To the hackmobile!

Turned out to not be too hard to reduce it to one file: Sitecore itself provides a MultiRootTreeList control that is used for rendering the insert data source item dialog (which supports multiple roots). With a little creative manipulation of the control tree, here we go:

And, the code (also as a Gist) - tested on Sitecore 7.2 Update-3 and Sitecore 8 Update-2:

using System;
using System.Linq;
using Sitecore.Diagnostics;
using Sitecore.Globalization;
using Sitecore.Shell.Applications.ContentEditor;
using Sitecore.Text;
using Sitecore.Web;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.WebControls;

namespace Kamsar.FieldTypes
{
    /// <summary>
    /// This field type is like a tree list, but you can specify more than one root item to select from (for example, videos or photos)
    /// The data source roots are specified using pipe delimiting just like regular Sitecore Query language
    /// </summary>
    public class MultiRootTreeList : TreeList
    {
        protected override void OnLoad(EventArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            base.OnLoad(args);

            if (!Sitecore.Context.ClientPage.IsEvent)
            {
                // find the existing TreeviewEx that the base OnLoad added, get a ref to its parent, and remove it from controls
                var existingTreeView = (TreeviewEx)WebUtil.FindControlOfType(this, typeof(TreeviewEx));
                var treeviewParent = existingTreeView.Parent;

                existingTreeView.Parent.Controls.Clear(); // remove stock treeviewex, we replace with multiroot

                // find the existing DataContext that the base OnLoad added, get a ref to its parent, and remove it from controls
                var dataContext = (DataContext)WebUtil.FindControlOfType(this, typeof(DataContext));
                var dataContextParent = dataContext.Parent;

                dataContextParent.Controls.Remove(dataContext); // remove stock datacontext, we parse our own

                // create our MultiRootTreeview to replace the TreeviewEx
                var impostor = new Sitecore.Web.UI.WebControls.MultiRootTreeview();
                impostor.ID = existingTreeView.ID;
                impostor.DblClick = existingTreeView.DblClick;
                impostor.Enabled = existingTreeView.Enabled;
                impostor.DisplayFieldName = existingTreeView.DisplayFieldName;

                // parse the data source and create appropriate data contexts out of it
                var dataContexts = ParseDataContexts(dataContext);

                impostor.DataContext = string.Join("|", dataContexts.Select(x => x.ID));
                foreach(var context in dataContexts) dataContextParent.Controls.Add(context);

                // inject our replaced control where the TreeviewEx originally was
                treeviewParent.Controls.Add(impostor);
            }
        }

        /// <summary>
        /// Parses multiple source roots into discrete data context controls (e.g. 'dataSource=/sitecore/content|/sitecore/media library')
        /// </summary>
        /// <param name="originalDataContext">The original data context the base control generated. We reuse some of its property values.</param>
        /// <returns></returns>
        protected virtual DataContext[] ParseDataContexts(DataContext originalDataContext)
        {
            return new ListString(DataSource).Select(x => CreateDataContext(originalDataContext, x)).ToArray();
        }

        /// <summary>
        /// Creates a DataContext control for a given Sitecore path data source
        /// </summary>
        protected virtual DataContext CreateDataContext(DataContext baseDataContext, string dataSource)
        {
            DataContext dataContext = new DataContext();
            dataContext.ID = GetUniqueID("D");
            dataContext.Filter = baseDataContext.Filter;
            dataContext.DataViewName = "Master";
            if (!string.IsNullOrEmpty(DatabaseName))
            {
                dataContext.Parameters = "databasename=" + DatabaseName;
            }
            dataContext.Root = dataSource;
            dataContext.Language = Language.Parse(ItemLanguage);

            return dataContext;
        }
    }
}

Have fun!

Blogging with Hexo - a Node.js detour

For the last couple years, I’ve run my blog from GitHub Pages using a static site generator, specifically Octopress. Static Site Generators are more or less a basic CMS for technical folks - you define your layout template(s) and then write content that inherit one of those layouts - say, a blog post. When you’ve authored your post you “bake” the site using the SSG tool, which takes the page layout and combines it with your content items and then spits out static HTML pages and assets. You then can upload the 100% static HTML site to a hosting service - such as GitHub Pages, Heroku, or Azure Websites.

Using a static site generator might seem quite limiting at first - after all, highly dynamic CMS like Sitecore would never work with HTML files and no database. So yes - you give up personalization. You give up any sort of server-side logic. You have to use JS-based commenting (e.g. Disqus, FB comments).

But you gain a lot as well by using such a tool. Ever hacked a static HTML site? Thought not. When was the last major WordPress security hole that demanded you to upgrade now? Yeah - last week. With a staticly deployed site you can also use the full branch and merge power of Git to keep a permanent history of your posts - and even accept pull requests. You’ll also never have to worry about backend performance - there is no backend. Authoring static sites can be done in powerful meta-languages, like writing posts in Markdown, CSS with SASS, and JS with Browserify. And finally, there are completely free hosting services for static sites - such as GitHub Pages - so it can cost nothing to host a static blog.

Enter Hexo

My previous Octopress blog suffered from an annoying problem: it was a huge pain to set up the generation environment on Windows, because it depended on Ruby, Python, Ruby DevTools, and a host of other very specifically versioned libraries. Not fun - in fact, I resorted to authoring all my posts on OS X. I started to look for something better.

It turns out there are just a few static site generators out there, in about every programming language known to humanity. I evaluated a number of them and settled on Hexo, which is written in Node. “But you’re a C# developer,” you say. In this case the C# options (like Pretzel) are significantly less mature - and I like that I can run Hexo on any platform because it’s JavaScript.

Setting up Hexo was very simple and took about 5 minutes. No really, the whole set of commands you need are on the front page of the Hexo site (well, except “install Node.js first”). I was able to import all my Octopress posts nearly unmodified, and tweak the base URL settings to keep my faux-wordpress URL scheme intact.

Then I wrote this post by simply entering hexo new post "Blogging with Hexo - a Node.js detour" at a command prompt, opening the file in Sublime Text, and writing my Markdown. I previewed it while writing using hexo server, which starts a HTTP server you can see the rendered page on. When I deploy it to the blog, all I’ll have to do is hexo deploy at a command prompt and all the git magic will be done by Hexo.

Neat, huh? And you can even read the source.

Synthesis 8.1 Released

Synthesis 8.1 has been released to NuGet. This is a minor feature release that also resolves an issue with the model provider caching in Synthesis 8.0.

DPI-aware image support

The new @Html.DpiAwareImageFor() MVC helper method emits a srcset along with the image that enables “retina images” served from the media library. To use it, you basically upload the image 2x (or 3x for the highest DPI devices) larger than it would normally display. Devices that support the higher resolution will automatically acquire the higher resolution version, and lower resolution devices will use the regular version.

Note that this is only for DPI-aware images. The more advanced forms of srcset and picture that enable viewport-based features (‘responsive images’) are not supported at this time. Last I checked not well supported by browsers either.

WebActivator removed as a dependency

Synthesis 8.0 depended on WebActivator to register its startup tasks. In 8.1, these have moved to the more Sitecorian initialize pipeline.

Improved config schema

The Synthesis.config file has been broken into three files: Synthesis.config (global model configuration), Synthesis.ControlPanel.config (enables the control panel page), and Synthesis.Startup.config (enables on-startup sync checks and regeneration). This makes it much easier to deploy Synthesis to a Content Delivery server, as you can simply delete all but Synthesis.config and be secure.

Upgrade Instructions

Synthesis 8.1 is a NuGet upgrade away. However to cover the new configuration changes, you do need to make a couple tweaks to an existing Synthesis.config.

  • remove <registerDefaultConfiguration value="true" /> (Synthesis 8.0 only)

  • remove the whole <synchronizationSettings> node in Synthesis.config (its values now live in Synthesis.Startup.config)

  • remove pipelines/httpRequestBegin in Synthesis.config (values now live in Synthesis.ControlPanel.config)

  • add default configuration registration to Synthesis.config <pipelines>:

      <initialize>
          <!-- REGISTER DEFAULT CONFIGURATION
              If this processor is registered, the configuration values below for providers are loaded into a Default Configuration.
              This enables Synthesis to work out of the box if you do not need multiple configurations.
                          
              For multiple configurations you may leave this active if you want to keep the default configuration and add your own on top of it,
              or remove it to register only your own configurations. Configurations are registered by calling ProviderResolver.RegisterConfiguration()
              - e.g. in more initialize pipeline processors.
                          
              NOTE: Do not register multiple configurations that contain overlapping templates.
          -->
          <processor type="Synthesis.Pipelines.Initialize.RegisterDefaultConfiguration, Synthesis"/>
      </initialize>
    
  • if using the optimizeCompilations setting to speed up Sitecore 8 startup time, turn it off temporarily after the upgrade or clear your temporary asp.net files folder, because the helper structure changed slightly during the upgrade and the cached razor files will be invalid.

Announcing Synthesis 8.0

I am happy to announce the availability of Synthesis 8.0. Synthesis is an object mapping framework for Sitecore that takes advantage of integrating the code generation with the mapping framework. This enables very high speed object mapping, LINQ-to-indexes support, model sync checking, and deep interface support for template inheritance and unit testability.

What’s new in Synthesis 8.0

Sitecore MVC Support

There are relatively few reasons to stick with Web Forms any longer for Sitecore development. Synthesis 8 introduces full-scale Sitecore MVC support, including:

  • A high-speed model provider for view renderings: you can use @model IMySynthesisTypeItem transparently on view renderings
  • HTML helpers designed to make it easy to work with Synthesis models and enable Experience Editor (e.g. @Html.ImageFor(x=>x.MyImageField))
  • Invalid model types on view renderings are trapped and contained to only the rendering involved, preventing the whole page from exploding due to one rendering failing. Messaging is shown to preview and editing users to show the failed rendering.
  • Diagnostic HTML comments are injected around renderings when dynamic debug compilation is enabled, showing the start and end of each rendering, its name, render time, and output cache diagnostics.

The functionality of the Synthesis.Mvc package is largely similar to Blade combined with Synthesis.Blade except that Blade is for Web Forms and Synthesis.Mvc is for Sitecore MVC. The Synthesis.Mvc HTML helpers are fully compatible with Synthesis.Blade’s.

Multiple configurations

Synthesis now supports more than one model configuration. This enables, for example, generating a separate model per-site for a multi-site installation of Sitecore. The additional configurations are registered similarly to MVC areas, using either WebActivator, the <initialize> pipeline, or Global.asax. There is some basic documentation available.

Configurations may also be friends, which enables sharing template classes across configurations that are aware of each other. For example, if you have a ‘shared’ set of templates that multiple sites’ templates derive from, making the shared model a ‘friend’ of your site model will enable your site model to derive from the shared model’s interfaces.

New control panel

Synthesis 8 uses a control panel that is hooked from the httpRequestBegin pipeline instead of using a HTTP handler and HTTP module. This enables Synthesis to require no web.config changes at all to install or remove. The control panel is multiple-configuration aware.

This control panel uses a configurable activation URL to allow you to put it where you want it. The default is /synthesis.aspx.

Installation and Upgrade

Synthesis 8 is available from NuGet right now. Initial installation is as simple as installing the Synthesis NuGet package (and, if you want MVC support the Synthesis.Mvc package). There is a README that opens after installation that helps you get started and configure it.

Upgrading does require merging the current Synthesis.config with your existing one. A few settings have been added or modified in this version to support the control panel and multiple configurations. You will also need to remove the Synthesis HTTP handler and HTTP module from web.config if you have them registered. Otherwise upgrade is as simple as upgrading the NuGet package and, if appropriate, installing the MVC package.

Synthesis 8.0 is designed for Sitecore 7.2 and later due to content search API versioning, and was primarily developed and tested on Sitecore 8.0 Update-1.

Under the hood changes

  • Modular generator: The code generator has been refactored and improved into a two-stage design where metadata (e.g. template hierarchy) is generated first, and passed to a code generator. This enables plugging in custom code generators if desired (if you’re feeling brave, it should be completely possible to say emit a Glass model from Synthesis’ generator). Metadata generation also enables multiple configurations to refer to each other.
  • Sitecore-isolated generation classes: All providers involved in generation no longer have any direct hooks to the Sitecore API. This hypothetically enables non-Sitecore database datasources for generation - for example, .item files on disk.
  • The default TypeListProvider allows for wildcards when specifying assemblies to scan for model types. Useful for cases where you have an assembly per site and don’t want to register them all individually.
  • The NuGet package now includes a README file that provides some basic directions for getting started with Synthesis, as this has been a previously lacking area of the documentation
  • Generated Synthesis models are now less prone to causing SCM merge conflicts. The Synthesis version stamp has been reduced to x.x instead of x.x.x.x on attributes, and the ‘generated by .net framework version x’ is removed from the header, which could cause problems if one developer had say .18072 and the other .17345; producing constant pointless model changes in the repository.
  • IStandardTemplateItem now has a Children property, which is an alias to .Axes.GetChildren(), to make it feel more at home for those used to the Item API.

Bug fixes

  • There was a problem with the way the template inheritance cycle rejection was implemented in 7.3.3 that caused multilevel inheritance on templates who had fields named the same as their template would generate invalid models. This has been fixed.
  • Setting the value of a HyperlinkField.Href with an external URL value (e.g. http://google.com) would cause it to save the link as an internal link type and Sitecore to flag it as a broken link. These are now correctly set as link type external.
  • When using LINQ-to-indexes and calling the GetResults() extension method, an exception will no longer be thrown. The exception is due to some misbehaving private reflection deep in Sitecore, and the workaround is even more private reflection. The authorities have been notified ;)

Sitecore 8 Experience Editor Performance Optimization

Sitecore 8 is pretty nice, but not without its share of rough edges. One persistently annoying issue I came across is that after you compile your solution in Visual Studio, it is glacially slow to start up in Experience Editor (formerly Page Editor) mode. Given that most sites built in modern Sitecore fashion are using component based architecture that is Experience Editor centric, this is a big drag on development time.

In this post I’ll outline the story so far, and some tweaks you can perform to improve the performance of Sitecore 8 after a compilation.

As a baseline, on my i7-3770k, 32GB RAM, and all-SSD system EE 8.0 takes 1:30 to startup after a compile. Yeah, a minute and a half. Sitecore 6.5 will start in the same situation in 0:21.

Option 1: Precompilation

John West and Kevin Obee noted that I should try disabling the SPEAK precompilation features. These are in the <initialize> pipeline and registered in Sitecore.Speak.config and ContentTesting\Sitecore.ContentTesting.config. If you comment these out, you trade having the SPEAK interfaces come up slower the first time (because they are not precompiled) for faster initial startup time (because you skip precompiling).

With those two precompilers commented out, my startup time dropped massively to 0:41. Still twice as slow as Sitecore 7.2, but oh so worth it when you’re compiling all day.

Option 2: Optimize Compilation

Still unsatisfied with spending 20 seconds compiling unchanged .cshtml SPEAK views every time I compile my application, I started looking around into the actual compilation process. An interesting facet of this issue is that it’s not triggered by simply restarting the app pool. You must touch an assembly in the bin folder to trigger the slow startup.

A clue came in the form of this StackOverflow answer from @pbering. He mentioned enabling the optimizeCompilations setting in the web.config. What does this do? Well, off to MSDN. If you read this document, it makes it clear that when you change a top-level file (which includes anything in bin) it invalidates all dynamically compiled assets because a dependency of their compilation has changed. Razor files, such as what SPEAK uses, are dynamically compiled - .NET parses them, compiles them to a C# class, and stores them off in the Temporary ASP.NET Files folder.

So essentially what happens is that Sitecore 8 depends on a WHOLE LOT of dynamically compiled SPEAK renderings. When you start it up the first time, ASP.NET compiles them and stores them in its compilation cache. As long as you don’t change any dependencies - e.g. dlls, global.asax - .NET can update the cache selectively when the cshtml file is changed, and it’s fast. But as soon as a dependency is changed - e.g. your site dll - .NET throws out the whole site’s cache and compiles it all again, just to be safe. With Sitecore 8, this takes 20-60 seconds at least.

You can instruct .NET to ignore dependency changes and only recompile dynamically compiled files when the file itself is modified. This has some potential dangers if you modify a dependency without changing the dynamically compiled file and make a breaking change; see the MSDN article for details of the things to be aware of if you enable optimization.

The good news is, if you turn on <compilation optimizeCompilations="true"> in your web.config, there is no longer any SPEAK recompiling on startup! Even better, it starts up in 0:13, beating 7.2 by 8 seconds!

That said, be aware that there are significant issues to be aware of when enabling optimizeCompilations. Read the MSDN article. I have not deeply tested using this setting, other than it removes the startup speed issue. If you run into problems, stopping IIS and clearing the Temporary ASP.NET files folder should clear it up. Rebuild may not help.

Option 3: Disable the SPEAK Experience Editor

A separate ticket on Sitecore support (relating to EE in Sitecore MVC) rustled up this other possible solution: disable the SPEAK-based Experience Editor, and go back to the Sheer one from previous Sitecore versions. This removes all cshtml compilation issues from the equation, and feels slightly faster in the browser to me. It has a less-polished UI appearance however, likely due to it not being a priority to reskin :)

To disable the SPEAK EE, open App_Config/Include/Sitecore.MvcExperienceEditor.config. Locate the comment around like 33 regarding ‘uncomment the page extenders below to switch to sheer’ and follow the directions in the comment.

Hope that helps!

Synthesis 7.3 released

Synthesis 7.3 has been released to NuGet and GitHub.

The big new feature in 7.3 is the Synthesis.Mvc package, which adds a Synthesis-compatible Sitecore MVC model resolution mechanism. This enables you to create View Renderings that transparently can use a Synthesis type as a model without any additional work:

@model IFooItem

<h1>@Html.TextFor(x => x.SomeSitecoreField)</h1>

The Mvc library also includes:

  • Helpers to make it simple to render Synthesis fields (like TextFor above). If you’ve ever used Blade these helpers are essentially identical.
  • Rendering diagnostics, also similar to Blade, which adds HTML comments around renderings with useful data - like whether it was output cached - whenever the site is run with debug compilation enabled. A great tool if you work with frontend devs who never know what rendering markup came from.
  • Altered handling of invalid rendering model types. By default, an exception that takes the whole page down is thrown if a view declares an @model and receives something other than that type. This can cause issues if your datasource item is ever an invalid item ID or something similar. Synthesis.Mvc changes this behavior by simply hiding renderings with invalid datasource types; if in preview or edit mode a message is shown in place of the rendering explaining why it’s hidden.

Installing Synthesis.Mvc is easy: Just add the NuGet package to your web project. It consists of a single assembly in /bin and the Synthesis.Mvc.config file that registers pipelines in /App_Config/Include.

Bug fixes

Several bugs were also fixed in Synthesis 7.3:

  • The mechanism Synthesis uses to generate media URLs was simplified as Sitecore 6.5 is no longer supported. This makes the media URLs on image and file fields valid in all cases, even when forcing media to have the server in the URL. Thanks to Jeremy Clifton and Robert Pate for the PR.
  • The Synthesis-wrapped version of Axes.GetPreviousSibling() incorrectly called GetNextSibling() internally. Thanks to @ullmark for the PR
  • If two templates formed an inheritance cycle, generating Synthesis would cause a stack overflow. This is no longer the case, however it will still emit code that won’t compile (as the interfaces will create a cycle in C#). Thanks to @GreyGhostStudio for the issue report.
  • The constructor of TestNumericField incorrectly took an int? when it should have been decimal?. Thanks to Robert Hardy for the PR.

Upgrading to 7.3

The configuration format for 7.3 has no changes, so upgrading is as simple as upgrading your NuGet packages. The Mvc support is a new separate NuGet package that would need to be installed.

Quick note: Sitecore MVC partials

Here’s a bit of an obtuse trick that lets you use @Html.Partial() effectively on Sitecore MVC View renderings without specifying the full path to the partial you want to render. You might think that regular MVC syntax would work here:

@Html.Partial("_MyPartial")

But you’d be wrong. Instead, you’ll get an error that the partial could not be found, and the perplexing message that it tried to search [path-to-views]/Sitecore/_MyPartial.cshtml. Where’d that “/sitecore” come from? To understand this, a bit of background on how ASP.NET MVC resolves partials is in order.

The view resolution convention is based on the controller name that executes the view, not the view’s physical location. This makes sense in a pure ASP.NET MVC environment where every view is the result of a controller. However in a View Rendering, there’s just the cshtml. Except that in the background, Sitecore executes the View Rendering using a shim controller - a shim that goes by SitecoreController. This is where the /Views/Sitecore search path comes from.

So what’s the trick? Well, as long as all your views are in a MVC-like hierarchy, you can refer to the partial using the parent path:

@Html.Partial("../ViewParentFolder/_MyPartial")

This jumps out of the controller rendering folder (always Sitecore) and lets you specify the parent folder directly instead, without resorting to a full absolute path which - especially if you use areas or moved views around later - could break.

In case you’re wondering why I’m using native partials instead of @Html.Sitecore().Rendering() or @Html.Sitecore().ViewRendering() and such, these are static components of a MVC layout that are shared between multiple layouts - so it doesn’t make much sense to also register them as dynamic renderings and take the performance hit of that lookup.