Take the community feedback survey now.

Vladimir Terziyski
Jul 2, 2010
  3831
(0 votes)

Using VirtualPathVersioningProvider in precompiled website

Versioning file system in EPiServer 5 is handled by VirtualPathVersioningProvider which is the default provider in EPiServer 5. Recently I had to resolve an issue with not registering the provider in precompiled website. There is a workaround here, but Coşkun's article shows how to register your custom provider, which probably won't require initialized EPiServer ClassFactory like the versioning provider. In my company we use such provider for some projects and this workaround works great. However, if you try to register EPiServer's versioning provider it will throw "ClassFactory not initialized" exception. This happens because somewhere deep in the constructor initialization logic of the provider there is a call to EPiServer.BaseLibrary.Context which requires Classfactory. Ted Nyberg wrote an improved version of Coşkun's fix but again he is using VirtualPathUnifiedProvider and not the Versioning provider.

If you examine EPiServer's global asax in reflector you will see that there is a call to SetupBaseLibrary (used for initialization of ClassFactory) which has to be called before InitializeVirtualPathProviders. Where these method are called depends on the EPiServer version for example in EPiServer CMS 5 SP2 they are located in Global class contructor. In the next service pack 3 - they called on the first request to the website:

   1: private void Global_BeginRequest(object sender, EventArgs e)
   2: {
   3:     if (_isFirstApplicationRequest)
   4:     {
   5:         lock (_setupLock)
   6:         {
   7:             if (_isFirstApplicationRequest)
   8:             {
   9:                 StaticInitialization();    
  10:     ...

Inside this StaticInitialization method there are calls to SetupBaseLibrary() and InitializeVirtualPathProviders().

This means that registering the Versioninng provider will work if it is called after SetupBaseLibrary()

In SP2 this is right in Application_Start method in Global.asax file. Here is the Ted's example modified to use Versioning provider:

   1: protected void Application_Start(Object sender, EventArgs e)
   2:   {
   3:       InitializeVersioningProvider();
   4:   }
   5:   
   6:   private void InitializeVersioningProvider()
   7:   {
   8:       // if current provider is not episerverversioning provider
   9:       if (System.Web.Hosting.HostingEnvironment.VirtualPathProvider.GetType() != typeof(VirtualPathVersioningProvider))
  10:       {
  11:           //Create a list of providers to add 
  12:           List<VirtualPathVersioningProvider> providersToAdd =
  13:              new List<VirtualPathVersioningProvider>();
  14:  
  15:           //Iterate through the virtual path declarations 
  16:           //in web.config and add a provider for each one 
  17:           foreach (ProviderSettings settings in EPiServerSection.Instance.VirtualPathSettings.Providers)
  18:           {
  19:               //Create a provider instance based on the 
  20:               //settings specified in web.config  
  21:               VirtualPathVersioningProvider newProvider =
  22:                   new VirtualPathVersioningProvider(
  23:                       settings.Name,
  24:                       settings.Parameters);
  25:  
  26:               //Add the provider to the list 
  27:               providersToAdd.Add(newProvider);
  28:           }
  29:  
  30:           //Loop through the providers to add and register them 
  31:           foreach (VirtualPathVersioningProvider provider in providersToAdd)
  32:           {
  33:               //Get a reference to the current  
  34:               //HostingEnvironment class 
  35:               //Note that a private member name belonging to 
  36:               //the .NET framework is used! 
  37:               HostingEnvironment he =
  38:                   (HostingEnvironment)typeof(HostingEnvironment).InvokeMember("_theHostingEnvironment", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
  39:  
  40:               //Ensure the hosting environment was retrieved 
  41:               if (he == null)
  42:                   return;
  43:  
  44:               //Use reflection to get a reference to the internal 
  45:               //RegisterVirtualPathProviderInternal method 
  46:               MethodInfo mi = typeof
  47:                  (HostingEnvironment).GetMethod
  48:                  ("RegisterVirtualPathProviderInternal",
  49:                  BindingFlags.NonPublic | BindingFlags.Static);
  50:  
  51:               //Ensure the method was retrieved 
  52:               if (mi == null)
  53:                   return;
  54:  
  55:               //Invoke the RegisterVirtualPathProviderInternal 
  56:               //method to register the virtual path provider 
  57:               mi.Invoke(he,
  58:                  new object[] 
  59:              { 
  60:                 (VirtualPathProvider)provider 
  61:              });
  62:           }
  63:       }
  64:   }

I've changed the first line to check if the current provider is not VersioningProvider, because using if(VirtualPathHandler.PageFolderProvider == null) will always fail. This is because Application_Start event is fired after EPiServer's InitializeVirtualPathProviders() so PageFolderProvider is not null.

In Service pack 3 the InitializeVirtualPathProvider is called on first request so global.asax has to be changed a little:

   1: protected void Application_Start(Object sender, EventArgs e)
   2: {
   3:        EPiServer.Global.Application_FirstBeginRequest += new EventHandler(Global_Application_FirstBeginRequest);
   4: }
   5:  
   6: protected void Global_Application_FirstBeginRequest(object sender, EventArgs e)
   7: {
   8:       InitializeVersioningProvider();
   9: }

In CMS 5 R2 SP2 version this provider initialization logic is moved to EPiServer.Web.InitializationModule class. One options is to put InitializeVersioningProvider in to a separate module and assure it is called after the EPiServer module. However I've didn't try this scenario.

Jul 02, 2010

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP - Opticon London 2025

This installment of a day in the life of an Optimizely OMVP gives an in-depth coverage of my trip down to London to attend Opticon London 2025 held...

Graham Carr | Oct 2, 2025

Optimizely Web Experimentation Using Real-Time Segments: A Step-by-Step Guide

  Introduction Personalization has become de facto standard for any digital channel to improve the user's engagement KPI’s.  Personalization uses...

Ratish | Oct 1, 2025 |

Trigger DXP Warmup Locally to Catch Bugs & Performance Issues Early

Here’s our documentation on warmup in DXP : 🔗 https://docs.developers.optimizely.com/digital-experience-platform/docs/warming-up-sites What I didn...

dada | Sep 29, 2025

Creating Opal Tools for Stott Robots Handler

This summer, the Netcel Development team and I took part in Optimizely’s Opal Hackathon. The challenge from Optimizely was to extend Opal’s abiliti...

Mark Stott | Sep 28, 2025

Integrating Commerce Search v3 (Vertex AI) with Optimizely Configured Commerce

Introduction This blog provides a technical guide for integrating Commerce Search v3, which leverages Google Cloud's Vertex AI Search, into an...

Vaibhav | Sep 27, 2025

A day in the life of an Optimizely MVP - Opti Graph Extensions add-on v1.0.0 released

I am pleased to announce that the official v1.0.0 of the Opti Graph Extensions add-on has now been released and is generally available. Refer to my...

Graham Carr | Sep 25, 2025