Episerver Forms: How to change where uploaded files are stored

During my session about Episerver Forms at the Øresund Episerver Developer meetup I received a question about how to change where uploaded files are stored

A quick look at how Episerver Forms manage the posted information I found that it is the DataSubmissionService that creates an Asset Folder and stores the file.

assetfolder

By replacing the original DataSubmissionService with a custom one that overrides the method StorePostedFile I could easily decide for myself where to store uploaded files.

Take a look at my example from GitHub.

Change access rights for Episerver Find UI

As you probably know, Episerver Find has a UI where the editors can see statistics on how their visitors use the search functionality, fine-tune their search results by adding best-bets, related queriessynonyms and boost results as well as get an overview what kind of information is indexed in the Find Index.

To see the menu items in the Episerver Find UI, the user needs to be a member of the following roles: “WebAdmins”, “Administrators”, “SearchAdmins” and these applies to all of the views: Manage, Configure and Overview.

To start with, see if you can setup your users and roles so that only those that should have access to the Find views are has any or these roles.

But I can’t!

Ok, let’s see how we can change this!

These roles come from the property AllowedRoles from EPiServer.Find.UI.FindUIConfiguration which is registered in the IOC for EPiServer.Find.UI.IFindUIConfiguration.

finduiconfiguration

How do I change this?

If you want to change this, you’ll need to change the registration for IFindUIConfiguration to your own implementation. This is easily done as I did with a “ConfigurableModule” my previous blog post about replacing the IContentTypeAdvisor registration.

However I only want to change the property “AllowedRoles” and looking at EPiServer.Find.UI.FindUIConfiguration I can see that the property is not virtual. Hence I can’t make my custom implementation inherit from the original implementation and just override AllowedRoles.

nosuitable

That shouldn’t be a problem? Just add new or copy the entire class!

I could solve that by writing public new string[] AllowedRoles but that is rarely a good practice!

So is copying the existing class and only change the AllowedRoles property, I don’t want to check that my custom implementation is in sync every time I update Episerver Find!

So I’m gonna make sure that my custom implementation wraps the original implementation in a private field.

public class WrappingFindUIConfiguration : IFindUIConfiguration
{
    private readonly IFindUIConfiguration _originalFindUiConfiguration;

    public WrappingFindUIConfiguration()
    {
        _originalFindUiConfiguration = new FindUIConfiguration();
    }

    public string AbsolutePublicProxyPath()
    {
        return _originalFindUiConfiguration.AbsolutePublicProxyPath();
    }
}

This looks better except that I’m now always counting on that Episerver will use the Episerver.Find.UI.FindConfiguration and that it will have an empty constructor.

Reuse the original implementation

To start with, I will create a constructor in my custom implementation that takes IFindUIConfiguration as parameter and set it to the private field. This can be seen in WrappingFindUIConfiguration.

Secondly I will need to make the ConfigurableModule do some more things before replacing the registration.

  1. Find the current registration of IFindUIConfiguration
  2. Remove it from the registration
  3. Register my custom implementation and make sure to use the constructor that takes the IFindUIConfiguration parameter.

To try this out without creating roles, you can simply add a virtual role that is valid as long as the user is member of WebAdmins or Administrators:

<configuration>
    <episerver.framework>
        <virtualRoles addClaims="true">
            <providers>
                <add name="MyCustomFindRole"
                     type="EPiServer.Security.MappedRole, EPiServer.Framework"
                     roles="WebAdmins, Administrators"
                     mode="Any" />
            </providers>
        </virtualRoles>
    <episerver.framework>
<configuration>

 

Customize “Suggested Page/Block types” when creating content

I’ve found a neat way to improve the editor experience – IContentTypeAdvisor and it can be found in the EPiServer.Cms.Shell.UI.Rest namespace of the assembly EPiServer.Cms.Shell.UI.dll.

This interface is used to populate the list of suggested Content Types when creating new content.

This interface has one method GetSuggestions which returns an collection of ids of block types and takes the following input parameters:

  • iContent Parent
    The parent item where the editor wants to create the new content.
  • bool contentFolder
    This is true if the editor is creating your new content within a Content Asset Folder.
  • IEnumerable<string> requestedTypes
    This is a list of the kind of content to create. The value comes from the UI and therefore they are just strings like “episerver.core.blockdata” or “episerver.core.pagedata”. If created through a component in the asset pane it can also have the value of the CreateableTypes.

The default implementation in Episerver is to suggest the same content types as already created.

defaultcontenttypeadvisor
An example of usage would be to help the editor create a slideshow where the slideshow including each slide in it are blocks.

So what I want to do is to suggest the Slide block if the editor already has created a Slideshow block in that same folder.

CUT TO THE CODE

First of all I’ve have some new Block Types, one for the Slideshow that has a ContentArea where you put each slide represented by a SlideBlock.

And I will need to create an implementation of the IContentTypeAdvisor.
[ServiceConfiguration(typeof(IContentTypeAdvisor))]
public class ContentTypeAdvisor : IContentTypeAdvisor
{
    public IEnumerable<int> GetSuggestions(IContent parent, bool contentFolder, IEnumerable<string> requestedTypes)
    {
        ...
    }
}

Note that I’m registering this to Episerver’s IOC using the ServiceConfigurationAttribute. This is to tell Episerver that I want to use this implementation.

Episerver looks for all registered implementations of this interface instead of just 1, therefore I don’t need to do anything with the previous registrations (unless I want to, see further down).

What I want the advisor to do is check is whether the parent has any children that is a Slideshow block. If so the advisor will suggest the Slide Block.

bothadvisors
This is quite easy as can be seen in my SlideshowContentTypeAdvisor.

It is also a good practice to check whether the suggested content type (in this case the Slide Block) is available as child to the content parent and that the editor has the proper access rights to create a Slide Block).

But I want to use my Content Type advisor INSTEAD of the Default one?

It’s easy to remove the already registered implementation of IContentTypeAdvisor by implementing the IConfigurableModule interface, remove the current registrations and to register your own implementation instead.

slideshoadvisor

Look at my DependencyResolverInitialization for that.

Disable the “Suggested Content Types” feature

Look at DependencyResolverInitialization and just don’t register your own IContentTypeAdvisor after ejecting the existing registrations.

This will remove all registered implementations and your editor will never see any suggested content types.

noadvisors

Tweaking and extending Episerver Forms – Part 2

This is a blog version of the presentation of Episerver Forms called “Episerver Forms – the new black?” I had on the Episerver developer Meetup in Stockholm February 9.

Episerver Forms was released from its beta stage just a couple of days earlier so we could take a look at what the final version looks like.

I will here cover the basics but you can find some more documentation on http://world.episerver.com/add-ons/episerver-forms/.

I have also updated my GitHub repository https://github.com/alfnilsson/EpiserverForms with my findings.

XForms – Out with the old …

First I had a quick review of the current editorial form management part of Episerver – XForms.

The Wikipedia article on XForms describes that it “is an XML format used for collecting inputs from web forms”, the first version standardized 2003 and the latest update was 2009.
Episerver took this standard and implemented it as a way to store the form specifications in Episerver CMS 4.60. However it has some good parts as well as some parts that leaves us wishing for more.

Pros

XForms

The Editor UI for XForms

  • The specifications for XForms is standardized format, meaning you can import and export them between other systems that support this standard.
  • Using a user interface, it’s easy for editors to create simple forms.
  • Developers can extend submitting and rendering using delegates & events.
  • Submitted information from the visitors can be exported to Excel (and XML) files.
    What I think is amusing is that the file is only a file containing a HTML table saved into a file with the file extension .xls, but Excel can handle it.

Cons

markup

Sample markup from an XForm

  • The forms that can be created are very basic!
  • Also the editor UI is very rudimentary
  • There are no language or versioning support
  • It is hard to organize the forms as you only have a one level folder system.
  • The rendering of the forms that you get out of the box use very bad markup with tables.
  • XForms is an old standard

… in with the new – Episerver Forms

The new editorial form management in Episerver is simply called Episerver Forms. As a developer you install it as a add-on from Episerver’s Nuget Feed. In November 2015 it became available as a beta and released live on Friday February 5 with Episerver – update 99.

I really like the fundamental idea in Episerver Forms where the specification of the form including the form fields is stored as Content, which means that rendering the form is made by the normal templating system in Episerver.
However I don’t agree on some other parts on how the form is managed.

Pros

forms

The editor UI for Episerver Forms

  • As Episerver Forms is based on Content, you also get some of the fundamental concepts in the same package such as
    • Versions
    • Localization
    • Folder structure
  • Built in form “fields”
    • Multi step forms
    • Upload files
    • Captcha
  • Submitted information from the visitors can be exported to XML, CSV & JSON
  • Built in support for confirmation and notification e-mails
  • Developer can extend submitting using web hooks and delegates & events
  • Developers can extend rendering using Views
  • Developers can create custom field types using BlockTypes
  • Developers can extend what to do when form is submitted by creating custom Actors.

Cons

  • Keep in mind as Episerver Form creates contens as you’re adding form and form elements. This might break content based license models.
    For Episerver Find you will manually need to tell Episerver Find to not index Form Container Blocks and
  • Out of the box JavaScript based with AJAX posts
  • Compromises and workarounds

So what about the new stuff?

Creating a form using the editor UI

forms ui.png

Creating and editing forms is basically the same as creating and editing Blocks.

The form itself is a Form Container Block (EPiServer.Implementation.Elements.FormContainerBlock) and the form elements inherits EPiServer.Forms.Core.ElementBlockBase.
Each element will be stored in the Form Contain Block’s Content Asset folder.

However the editor UI makes the block-part a bit abstract for the editor as there is a new component in the Assets Pane called Forms (1 on the image above).
This component is basically just a shortcut to the folder called “Episerver Forms” and here you can only create new Form Container Blocks and folders (2 on the image).

Form content and elements

As you’re editing your form, you can easily add new elements using the Gadget “Form Elements” (3 on the image) that automatically opens and drag them to the Content Area of your form (4 on the image).

There are also some content possibilities where you can add a heading and a description.

Form settings – Content tab

all properties

Switching to “All properties” you will see some more settings and content that you can apply.

Filling the field “Confirmation message” (2) displays an alert, for example “Are you sure you are ready to post?” (will not work without JavaScript)

After submitting the form, do you want the visitor to stay on the same page and replace the form with a “thank you” message, or redirect the visitor to a specific page? Set this in either “Display page after submission” (3a + 3b).

You can also add some behavior settings such as allowing anonymous (not logged on) users to submit the form and allowing same users to submit the form multiple times. Personally I always forget to check these ;)

You can also allow the submitted information to be read using the Service API.

Don’t ask me what you would do with Categories on forms though, this is built-in on all Blocks but can be hidden using this little hack.

Form settings – Settings tab

Settings

In the Settings tab you can set what you want to do when the visitor submits the form. In XForms this was something you set on the submit button but will now be something set on the actual form.

Storing data

First and foremost you can set that information should be stored. Form submissions will then be stored in the Dynamic Data Store (DDS) but there is an API that can be used to read the information.

view submitted

Stored data can also be seen and exported in the view Form Submissions.

Actors

You can add your own “actors” that will act on incoming information.

There are two built in actors that you can use but you can create your custom ones as well.

E-mails

In these e-mails you can set sender, recipient, subject and the message. All these fields can use “placeholders” that will fetch data from the visitor’s form submission.

email

Note that you should allow the server to send e-mails from the sender domain or there is a risk that your messages are classed as junk. This is done setting up a DKIM authentication.

Web Hooks

You can provide Web Hooks where the server will send the submitted information.
This will send the submitted in a JSON serialized format which is quire cryptic. I will mention this further down in the section about events.

Configuration

You can customize some parts of Episerver Form with configuration.

<episerverforms minimumAccessRightLevelToReadFormData="Edit"
	sendMessageInHTMLFormat="true"
	defaultUploadExtensionBlackList="asp,aspx,asa,ashx..."
	coreController="/EPiServer.Forms/DataSubmit"
	formElementViewsFolder="~/Views/Shared/ElementBlocks"
	workInNonJSMode="false"
	injectFormOwnJQuery="true">
  • minimumAccessRightLevelToReadFormData
    Set what level the editor requires to read the submitted information. For example read, or administer
  • sendMessageInHTMLFormat
    Do you want e-mail messages to be sent as HTML or plain text?
  • defaultUploadExtensionBlackList
    You can blacklist file types that should be available to upload using the File upload element (see below).
  • coreController
    Do you want to use another controller when submitting the form? Set the path here.
  • formElementsViewsFolder
    Set where you want to have your custom view templates that overrides the ones built in.
  • workInNonJSMode
    Do you want the form to work without JS? Who doesn’t so I don’t really understand this would be an opt-in? See more about my thoughts concerning the non-JS fallback below.
  • injectFormOwnJQuery
    As the template for the form is using JQuery you can tell Episerver Forms not to inject the library (a quite old version 1.7.2).
    This would be to prevent your own website’s JQuery to conflict with the one injected by Episerver Forms.

Working without JS

During BETA, the Form required JavaScript to work. Mainly to get the multi-step to work, but also to submit the form.

After multiple requests to make Episerver Forms to work without JavaScript, Episerver added a configuration setting to make this work.

And the “fallback” isn’t even good!

but-why.gif

Setting the configuration workInNonJSMode to “true” will make the form to make a good old HTTP POST Request to the controller.

If the submitted information does not validate, for example required fields are not filled or validation on e-mail addresses, the controller redirects the user back to the page containing the form with some querystrings that includes the problem.

non js

Not only can the querystring be modified to say something else, the field that the visitor had posted are cleared.

Refreshing the page after a successful or unsuccessful submit will also continue to display the message.

Extend rendering

The built in views are stored in the folder modules\_protected\EPiServer.Forms\Views\ElementBlocks and have the name as the BlockData class representing the element, for example TextboxElementBlock.ascx.

As you can set a folder for your custom views and override the existing ones, all you need to do is to add a partial view with the same name as the original.

Look at my custom view _TextboxElementBlock.ascx, rename it to not start with an underscore and it will be used to render Textbox elements.

The built in views are ascx files for Web Forms but the work in MVC websites as well.

Extend element types

It’s very easy to create your own element types. So easy that there already are some blog posts about it. By Arve Systad and by David Knipe.

select map.PNG

I made my own element type for my presentation that allows the visitor to select a location on a Google Map.

For this example I created a block type MapElementBlock and a view for it.

I used the JQuery plug-in “JQuery Location Picker” which meant that I needed to add a JavaScript file, insert it into the Bundle Config and add a reference to the Google Maps API into the layout.

To finalise the editor experience I needed to add a translation for my new content type.
Otherwise newly created form elements of this type will have a name that is an error message from LocalizationService about not being able to find a translation.

Built in fields

There are some nice fields that you can use. These does not exist in XForms and the customer’s were often asking the Episerver partners if they can be added (with some headaches and work they could)

File upload

A simple file upload form.You can set valid file types and a maximum file size.

The uploaded file will be stored in the Content Asset folder for the block representing the File Upload-field, just don’t rename them as the connection to the submitted data will be lost..

inception.png

This means that the file will have the same access rights as the File upload element, which in turn will have the same access rights as the form it belongs to.
Inception anyone? :)

Captcha

captcha

There are many ways to create a Captcha, this is a simple one that will create an image, and validate that you entered the text that was “visible” on the image.

Multiple steps

A simple way to create a step-by-step wizard. For each step the visitor completes, the information will be saved. You don’t need to wait for the visitor to finalize the form to see the information from the completed steps.

steps

You can also setup rules to display steps for visitors that entered specific values in values from previously completed steps.

multi step rules

Predefined lists

You can create predefined lists so that the visitor can select values based on something dynamic. This is used by creating a “FeedProvider” that implements EPiServer.Forms.Core.ExternalFeed.IFeedProvider.

Episerver Forms has a built in that can read from XML Feeds such as RSS. In Forms.config you can easily try one using the Episerver World Blog RSS Feed.

Extend submitting – events

You can extend what’s going on when submitting a form by hooking up to these delegate events:

  • FormsSubmitting
    Before each step, at least once
  • FormsStepSubmitted
    After each step, at least once
  • FormsSubmissionFinalized
    When final step is posted
  • FormsStructureChange
    When Form Container Block is published

Submitting forms

For each time the visitor submits the form or goes from one step (see multiple steps above) to the other, the FormsSubmitting will be fired.
As there is a built in multi-step support, FormStepSubmitted will always be fired at least once.
Once the customer submits the form, FormSubmissionFinalized is fired.

The data in the event arguments are a bit cryptic to determine which value belongs to which field.

submitted

For example my element Name” has the key “__field_182” as the Block representing this element has the Id “182”.

You can use my InitializationModule to see what kind of information is posted.

Change structure

As the Form stores the information in the DDS, the structure of the Store needs to be altered when you change the form structure (adding, removing, changing order of fields).

FormStructureChange is an event where you can listen to these activities.

Summary

I really like the concept with Episerver Forms, especially that it is based on Content and Templates.

However I see that there are flaws and compromises in the implementation of posting data. I hope this gets a look at in a version 2 in the near future.

I’ve got some ideas on how to make Episerver Forms to make a classic “Post to yourself” kind of Form that I hope I get some time to put it in code soon.

Take a look at my GitHub repository and feel free to give me some feedback with things you like/dislike with Episerver Forms. I would really like to hear if you have your own workarounds or ways to play around with the new Episerver Forms.

Tweaking and extending Episerver Forms

I’m really glad that Episerver is replacitng their Forms creation tool “XForms” and started to like Episerver Forms. Especially when it comes to a few highlights:

  • Forms and the form fields are Content Types. You can create custom markup for your fields by simply adding separate Views.
  • You can also extend and create your custom form fields by simply adding more content types. See Māris Krivtežs’ blog post about this.

However there are some areas I’m not that happy about.

Working with Forms in Edit mode

What I really like is how the Edit mode is extended so that the Editor doesn’t really need to work with the form as the Blocks it actually is. Edit mode has some new panes and thingies to easily work with the form.

edit mode - forms

But Episerver is using the normal Block preview template. But since everything is based on blocks this can easily be solved using a specific preview Controller and View for the Forms Container Block. In my example I have also added support for Element Blocks, even if they are only visible for a short moment when editing them.

Submitting Forms

One thing that annoys me a bit more is that Episerver Forms makes an AJAX request to submit the form. The reasons I don’t feel this is a good idea is because it’s not only making the site dependant on JQuery, if you’re already using JQuery the user will now download the JQuery library twice. Episerver Forms is using an old version of JQuery (1.7.2) from March 2012, I hope there won’t be any conflicts between your version and this one.

I’m trying to figure out what I can do to make Episerver Forms use a normal HTTP Request with POST to submit the forms instead but first I need to understand what the current controller “FormSubmitController” does.

I’ll dig deeper into this and get back to you.

My GitHub Repository for playing with Episerver Forms might be updated while waiting for the blog post.

Creating a Content Folder that only allows specific Content Types

If you need to organize the content among Assets, such as blocks and media, you can do this by creating your own Content Types that inherits from ContentFolder.

Unfortunately the Episerver UI only supports creating Content Folders in the folder section of the Asset pane, so you’ll need to find a way to create these new folders. If it’s a strict structure it’s very easy using the ContentRepository in Episerver. But if the editor should create them you’ll probably need to create a separate view for this or do some Dojo tweaks.

I might look more into the first option using some inspiration from Fredrik Vig‘s “Instant Templates“.

But for now, let’s focus on creating folders that only allows specific types.

Cut to the code

First of all, I need some Content Types that represents my folders – one that only allows Teaser Blocks and one that only allows Image Files, see Alloy Templates to look further into these two Content Types.

[ContentType(GUID = "964063f0-613b-4ce5-85a0-2d11fee0b905")]
[AvailableContentTypes(Availability.Specific, Include = new[] { typeof(TeaserBlock) })]
public class TeaserContentFolder : ContentFolder
{
}

[ContentType(GUID = "e730c883-f9b7-4d5e-b309-a00070159771")]
[AvailableContentTypes(Availability.Specific, Include = new[] { typeof(ImageFile) })]
public class ImageContentFolder : ContentFolder
{
}

At startup I will make sure that these two folders are created using an Initialization Module:

[InitializableModule]
[ModuleDependency(typeof(Web.InitializationModule))]
public class RestrictedContentFolderInitializationModule : IInitializableModule
{
    public void Initialize(InitializationEngine context)
    {
        IContentRepository contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();

    ContentReference siteAssetFolder = ContentReference.SiteBlockFolder;
        IEnumerable<ContentFolder> children = contentRepository.GetChildren<ContentFolder>(siteAssetFolder).ToList();

        CreateSpecificFolder<TeaserContentFolder>(children, "Teaser folder", siteAssetFolder, contentRepository);
        CreateSpecificFolder<ImageContentFolder>(children, "Image folder", siteAssetFolder, contentRepository);
    }

    public void Uninitialize(InitializationEngine context)
    {
    }

    private void CreateSpecificFolder<T>(IEnumerable children, string teaserFolderName, ContentReference siteAssetFolder, IContentRepository contentRepository) where T : IContent
    {
        if (children.Any(child => child.Name == teaserFolderName))
        {
            return;
        }

        var teaserFolder = contentRepository.GetDefault<T>(siteAssetFolder);
        teaserFolder.Name = teaserFolderName;
        contentRepository.Save(teaserFolder, SaveAction.Publish, AccessLevel.NoAccess);
    }
}

This will make sure that you’ll have two folders in the Assets Pane.

asset folders

So when I try to create any Blocks in the Teaser folder, I’ll only be able to create a Teaser block, and as usual when I’m only able to select one Content Type, it will automatically select it without giving me a list of available Content Types.

create teaser block

And when I try to upload files to the Image folder, I will only be able to upload files of that specific Media Type. Which in this example means, only images and not text files.

upload files

And when I try to create a Block in the Image folder, I will not be able to select any Block Types since none are available.

The code is also available on the GitHub Repository https://github.com/alfnilsson/RestrictedContentFolders

If you’re a Dojo Guru and have a way to tweak Episerver UI to allow the editor select which type of folder to create, please hit me up!

Code best practices and performance optimization – the summary

This is a summary of my session “Code best practices and performance optimization” that I held during Episerver (still trying to learn the new casing format) Ascend 2015 in Las Vegas and the Episerver Tech forum in Stockholm.

The session mentions in three areas some fundamental tips and tools on profiling your solution and how you can work with the Episerver CMS API.

  • Tools
  • Distractions
  • Scenarios
    • SessionState
    • Loading Content & Episerver API
    • Cache
    • Race Condition Locks

So let’s begin!

Tools

Here are some of the tools I used in my session to see what ails my application.

DotTrace

DotTrace from JetBrains is a cool tool that we use alot at NetRelations to monitor CPU and memory usage as well as keeping track on method calls and time in your application.

It has a quite high cost so you can find some other options such as the built in profiling tool in Visual Studio which is getting better through each version or ANTS Performande Profiler from Redgate.

However JetBrains are continously improving their tool continously and with their new Timeline reports I find it really useful keeping track of HttpRequests, SQL requests among other things!

DotTrace

SQL Server Profiler

Microsoft’s own SQL Server Profiler gives you a great overview about what’s going on at your SQL Server. It monitors database requests and can give you an overview about performance as well.

I would recommend that you’re using SQL Server Profiler in production environment with caution. It’s mostly in production you can get the best trackings but it can lower performance while profiling.

sql profiler

Distractions

While profiling your solution you want to focus on your pain points without any distractions. Otherwise it would be like a doctor investigating pains in a knee while someone is hurting the patient’s arm.

The easiest ways to reduce this in an Episerver solution is to disable scheduled jobs and to focus your Http requests.

Scheduled Jobs

Meanwhile you’re trying to profile your solution, you don’t want any unecessary activities. Here’s where Episerver’s Scheduled jobs can be quite annoying! But it’s very easy to deactive in web.config by setting enableScheduler to “false” on the episerver/applicationSettings element.

<configuration>
	<episerver>
		<applicationSettings
			enableScheduler=“false” />
	</episerver>
</configuration>

Frontend resources

While you’re using a browser to visit pages in your Episerver site, your browser will create more requests to download resources such as JavaScript and Stylesheets. Modern browsers also want to find a /favicon.ico file on the server.

More importantly the browser downloads images embedded in the page. As you probably know, images in Episerver are managed as content where each request will use the Episerver CMS Api and in turn make requests to the database.

Some tools that can be used to focus on your specific functions are creating a .NET Command Line based solution, but better up using LINQPad – a nifty feature where you can “code” simple C# code without creating an entire Visual Studio project.

Another useful tool for creating single custom Http Requests are the Chrome plugin Postman.

Personally I like LINQPad since you can do more things than only Http Requests, such as firing multiple ones at the same time using the script Ascend product pages.linq that I used while profiling with DotTrace.

Scenarios

I will now present some profiling scenarios and explain why I recommend that you try to avoid them.

In the code, found on my GitHub repository I have created a specific Interface called IStandardPageRepository. The purpose is to list StandardPages that are descendants to a specific page. I’m using this on a ProductPageController that I have added to a normal Alloy website. To test the performance I have also created a nested tree structure of StandardPages beneath each Product Page in the Alloy website – Alloy Meet, Alloy Track and Alloy Plan.

The implementation of IStandardPageRepository is registered using the ServiceConfigurator attribute and fetched by injecting it in the constructor of my ProductPageController.

SessionState

Using SessionState is a lovely feature where you can save information for the visitor between each request. However it has some faults that makes the website is perceived as slow. This is because .NET queues up each request from the same visitor so that Session information is synched between each request. This includes AJAX requests as well as the behavior of many visitors today where they might run your website in multiple tabs.

sessionstate

This is quite easy to fix by either adding the attribute [SessionState(SessionStateBehavior.Disabled)] to your MVC Controller or the attribute EnableSessionState=”false” to your WebForms registration directive.

sessionstate off

So what about your beloved Session information? Do you really need them? Try to build your solution so that you’re not depending on that kind of information between requests.

An approach I usually have is to stare a “session key” as a cookie and to store the information, such as the shopping cart, on the server. Just keep regional laws about what you’re allowed to store and require to inform your visitor in mind.

Also remember that third party add-ons and features such as some Visitor Groups might require SessionState to be enabled.

Cut to the Code

In the EmptyStandardPageRepository I have added a Thread.Sleep for 2 seconds to simulate a slow page request. By adding the SessionState attribute to the ProductPageController you can see the difference of having SessionState disabled by running your Alloy website and opening two of the Product Pages in separate tabs

Loading content and Episerver API

The most common function we use in Episerver is to load content in different fashions. I will go through some of the functions in the Episerver API and some pros and cons about them.

GetChildren

GetChildren might be one of the most used function in the Episerver API. It’s very easy to use and has some built in features to filter on Content Type and language.

However you’ll need to filter by access rights manually and whatever requirements you’ll have to select your content.

If you have a nested structure you’ll also need to recurse GetChildren for each and every child you find.

This can be seen in the GetChildren implementation of IStandardPageRepository. Here I’m only checking whether each content is a StandardPage but if you have more complex requirements this could be quite expensive.

GetDescendants and Get

Using GetDescendants in Episerver gives you a way to make a single request to receive a list of each and every descendent content.

However this returns a bunch of ContentReference instead of the actual Content, which can be used by the IContentLoader.Get method.

You’ll also need to check access rights and whatever requirements you’ll have which might make it quite expensive.

You can see an example of this in my implementation of IStandardPageRepository called GetDescendantsGet.

GetDescendants and GetItems

Not to forget that if you’re having a bunch of ContentReferences, you don’t need to iterate through these and run the IContentLoader.Get for each ContentReference.

Using IContentLoader.GetItems you can easier get each Content back. However you still need to check access rights and your other requirements about each content that might get expensive.

You can see more about this on the implementation GetDescendentsGetItems.

FindPagesWithCriteria

Here I’ll start focus on database requests and caching by looking at FindPagesWithCriteria which I think is a missunderstood function in Episerver.

It’s not a very precise feature which unfortunately only works with Pages at the moment. But if you have some basic requirements to get your content it works as a charm.

Looking at the implementation called FindPagesWithCritera you’ll find how I’m creating a criterion to find all pages that are Standard Pages.

Just don’t forget to cache the result since it will ALWAYS ends up in a database request using the stored procedure netPropertySearchValueMeta.

Caching

In Episerver you can find two Interfaces that concerns caching, IObjectInstanceCache which in its default implementation wraps HttpRuntime.Cache and ISynchronizedObjectInstanceCache which use IObjectInstanceCache and adds some synchronization to a Load Balanced environment.

ISynchronizedObjectInstanceCache is also found with EPiServer.CacheManager but of course we’d rather prefer using Interfaces and Episerver’s IOC management.

var cache = ServiceLocator.Current.GetInstance<ISynchronizedObjectInstanceCache>();
cache.Insert(key, value, cacheEvictionPolicy);

synchronized cache

You can also work with a CacheEvictionPolicy to determine when the cache should be cleared. It could either by how long it should be stored in the cache, or set a dependency on other cache keys.

new CacheEvictionPolicy(new string[] { "cacheKey" });

The main difference between common cache keys and master are that master keys are not required to exist in the cache while cache keys do

new CacheEvictionPolicy(
	null, // for files
	null, // for cacheKeys
	new string[] { "masterKey" });

cachekeys

You can see how I’m caching the result of my CachedFindPagesWithCriteria, as you can see I have also added a Thread.Sleep and this will be covered in my next scenario about Race Condition Locks.

In a real world sitation it’s a more common practice to cache the ContentReference instead of the actual Content so that the editor won’t need to wait for the cache to expire for their updates to show, or that you’ll need to write unecessary cache clearing mechanisms.

Race Condition Locks

As mentioned previously, there’s a strange Thread.Sleep before I’m adding the PageDataCollection into the cache. This is to simulate that something is taking an amount of time to perform which might lead to things being run even if they shouldn’t.

Having SQL Profiler monitoring your database and running the LINQPad script Ascend Product pages cached.linq will show you that the first 2 requests are running the stored procedure netPropertySearchValueMeta twice while the third one doesn’t due to the result being cached.

Some resources can also lead to an Exception if two threads (for example two visits your your IIS application) are trying to access it.

Simple lock

Here is where Locking can come handy. The simple version is a simple Lock that makes sure that the second threads waits until the first are finished, and in my example also has stored the result in the cache. You can see an example of this in LockingFindPagesWithCriterion.

Note that after the lock I’m checking the cache again and that is because the locked threads needs to take another look in the cache after they’ve been waiting for the first one to perform its work and cached it.

A bad side in my example is that other threads that will need to perform the implementation of  LockingFindPagesWithCriterion based on another root node needs to wait for the first ones to finish before they can do their work.

This can be seen with the LINQPad script Ascend Product pages cached 2.linq.

Mini locking

This is where we can add a more granular locking mechanism by using mini locking.

Instead of having a static object as a lock, we’re using a ConcurrentDictionary<string, object> as a collection of locks. ConcurrentDictionary is a thread safe version of the dictionary and works good for this as you can see in the implementation MiniLockingCachedFindPagesWithCriterion.

Wanna play?

If you want to play around with the code examples from my session, you’ll find them on the GitHub repository https://github.com/alfnilsson/ascend2015. You can also find my presentation as PDF here.

These are just some basic steps to start improving and monitoring your solution. If you have other tips or tools that you use to on how to improve performance, feel free to comment this post.