Take the community feedback survey now.

Daniel Ovaska
Aug 10, 2009
  6335
(0 votes)

Xforms performance

Introduction

The main issue is that the XFormSelect.aspx does a lot of database calls to load each xform. You can check the bug #25759: EPiServer.UI.Edit.XFormSelect.LoadForms calls GetxFormUsedonPages twice per xform on each request.

The problem is that GetxFormUsedonPages results in a call to the FindPagesByCriteria method. If you haven’t been warned about using that method extensively, you should have been. So the bottom line is that if you have 200 xforms this will result in 2*200=400 FindPagesByCriteria calls every time the popup is opened / paged / filtered which hammers the database badly and can result in deadlocks. Response time at worst for me was around 120 seconds which causes a timeout error.

Solution

Warning: This solution modifies some files in the episerver UI folder. This will have to be redone after upgrading episerver. If possible, wait until episerver implements some similar solution. I did not have that option with a lot of angry editors on my back. If you do not have the privilege of time, feel free to use my workaround.

  1. Locate and backup the modified UI files (XFormSelect.aspx, XFormSelect.ascx, XFormEdit.aspx)
    These are usually found at C:\Program\EPiServer\CMS\5.2.375.133\Application\UI\Edit when doing a standard install.
  2. Replace the files above with the
  3. Add some logging, change namespaces etc to fit your needs.
  4. Add these files and their code behind files (.cs) to your solution. 
  5. Add the XFormManager.cs to your solution.
  6. Open your Global.asax and add the following lines:
    a)  If you haven't added some page events. Do it…
    protected void Application_Start(Object sender, EventArgs e)
    {
        EPiServer.DataFactory.Instance.CreatedPage += 
    new PageEventHandler(onCreatedPage); EPiServer.DataFactory.Instance.DeletedPage +=
    new PageEventHandler(onDeletedPage); EPiServer.DataFactory.Instance.SavedPage +=
    new EPiServer.PageEventHandler(OnSavedPage); }
    b) Add event handlers if you don’t have any. 
    private void onDeletedPage(object sender, PageEventArgs e)
    {
       PageData deletedPage = 
    EPiServer.DataFactory.Instance.GetPage(e.PageLink); InvalidateXFormCache(deletedPage); } private void OnSavedPage(object sender, EPiServer.PageEventArgs e) { PageData updatedPage =
    EPiServer.DataFactory.Instance.GetPage(e.PageLink); InvalidateXFormCache(updatedPage); } private void onCreatedPage(object sender, PageEventArgs e) { PageData createdPage =
    EPiServer.DataFactory.Instance.GetPage(e.PageLink); InvalidateXFormCache(createdPage); }
  7. c) Add private helper function to invalidate xforms cache for that page.
    private void InvalidateXFormCache(PageData page)
    {
       try
       {
           foreach (PropertyData prop in page.Property)
           {
              if (prop.Name == "XForm")
              {
                 if (prop.Value != null)
                 {
                      string formid = prop.Value.ToString();
                      if (!string.IsNullOrEmpty(formid))
                      {
                         string cacheKey = "xFormUsedonPages" + formid;
                         HttpContext.Current.Cache.Remove(cacheKey);
                      }
                 }
               }
             }
         }
         catch (Exception ex)
         {
             //Do some logging with log4net for example
         }
    }
  8. Build and try it out and add a comment on this blog

Summary

To solve the bad performance with xforms selection and the deadlocks in the database this can cause I added caching in a helper class (XFormsManager) and redirected the calls from XFormSelect.ascx and XFormEdit.aspx to use this class instead. This reduced the response time from 120 seconds to a few ms. As the XFormSelect page also displays which pages use which form, I added eventhandlers to Global.asax to ensure that these text were updated.

Aug 10, 2009

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