Comments to Frederik Vig’s blog series
Frederik Vig in Norway has started publishing an excellent blog post series on how to set up an EPiServer site from scratch. This post mainly aims to complement Frederik’s posts with some comments and pointer that I find valuable.
Update: You may also be interested in how to set up an EPiServer website using EPiServer Template Foundation.
Talking points
- Base classes for master pages, page templates and user controls
- Master page structure
- PageTypeBuilder and page type inheritance in EPiServer
- Project folder structure
- Build-specific configuration files
- Basic configuration changes for performance
Build-specific configuration files
- Create a folder called [Configuration] in your project root
- Underneath it create subfolders for each build configuration you have (Release and Debug are default)
- Create a pre-build event (the Build Events tab among the project properties) to copy all .config files from the corresponding folder to the website root:
copy "$(ProjectDir)[Configuration]\$(ConfigurationName)\*.config" "$(ProjectDir)" /y
- Extract build-specific configuration elements into separate configuration files
- Modify web.config to include build-specific elements from the external files
We keep web.config in the site root, but we extract all build-specific configuration elements to separate .config files and put them in their respective build configuration folder:
For example, we cut out the entire <episerver> element and put it in a file called episerver.config (I usually name the file according to the pattern elementname.config):
Next we modify web.config to include the <episerver> element from the episerver.config file:
Update: With Visual Studio 2010 you can create config transforms for managing build-specific configurations instead, see the post on using config transforms for EPiServer settings.
Solution folder structure
Some choose to keep the VPP folders on a shared file server (I prefer this myself), but if you don’t you should create a folder for your project and within it create one folder the website files and one for the VPP files.
You should keep the solution file on a level beneath the project folder (called Website in my case). This is particularly important if your using Team Foundation Server for versioning and source control:
Project folder structure
I usually opt for a project folder structure similar to that of the EPiServer Templates project (with a few additions):
Update: This article was migrated from the old blog at tednyberg.com. We no longer have a Classes folder, instead we use folders mapping 1-to-1 to descriptive namespaces. See New EPiServer website using Template Foundation for details.
I put all external assemblies (such as those for EPiServer) in the folder called [Libraries]:
Then I reference the required assemblies from the [Libraries] folder…
…and I set the Copy Local property to true for these references to ensure the assemblies are copied to the bin folder when I build my project:
Note: If you do like me and keep all EPiServer assemblies in the [Libraries] folder you need to reference all of them and set Copy Local to true in order for your EPiServer website to run with all features. Another approach is to copy binaries from the [Libraries] folder with a pre-build event (similar to how we did with the configuration files earlier).
Also note that I’ve added a reference to PageTypeBuilder (more on that next).
Create your own EPiServer base classes
This is really important from an architecture and extensibility point-of-view: always create custom base classes for EPiServer templates, user controls and master pages!
I’m a big fan of Joel Abrahamsson’s PageTypeBuilder project for creating strongly typed page types. If you still haven’t tried it make sure to check out my introduction on PageTypeBuilder.
My project name can be abbreviated “FT”, so I’ve prefixed my base classes with those letters.
I’ve created a class called FTTypedPageData inheriting from the TypedPageData class of PageTypeBuilder:
I could use this page type base class to add site-wide page properties and helpers like the following to get the current page’s title with the site name appended:
public string PageTitle
{
get
{
return string.Format("{0} - {1}", PageName, Settings.Instance.SiteDisplayName);
}
}
Then I’ve created a template page base class using PageTypeBuilder’s generic TemplatePage class:
You will want your user control base class to inherit PageTypeBuilder’s generic UserControlBase class:
My master page base class still inherits from the standard ASP.NET MasterPage class:
One handy addition to the master page base class could be a CurrentPage property to allow us to access the current page in the master page code-behind file (this is a bit verbose since we want a PageTypeBuilder-typed object):
public TypedPageData CurrentPage
{
get
{
return (FTTypedPageData)new LoadTypedCurrentPage<FTTypedPageData>(HttpContext.Current.Handler as PageBase).CurrentPage;
}
}
Or, if you use the start page for storing site settings you could add a property like this one to always have a strongly typed start page object available in your master pages:
public PageTypeHome StartPage
{
get
{
// Get a strongly typed start page object
return (PageTypeHome)DataFactory.Instance.GetPage(PageReference.StartPage);
}
}
If you don’t use PageTypeBuilder
If you do not use PageTypeBuilder you should still create your own base classes. In that case simply inherit from EPiServer’s base classes.
It’ll look something like this for the template page base class:
You then use that base class for all page templates (making site-wide template customizations and extensions a lot easier):
Multiple master pages
Which master page structure is most appropriate obviously depends on your site and its layout, but I usually keep something like this:
Root is the core HTML foundation, basically everything except the <body> element content:
<%@ Master Language="C#" AutoEventWireup="false" CodeBehind="Root.master.cs" Inherits="MyNamespace.Templates.MasterPages.Root" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title></title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<link rel="stylesheet" type="text/css" href="/Templates/Styles/main.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" />
<script type="text/javascript" src="/Templates/Scripts/main.js" />
</head>
<body>
<form runat="server">
<asp:ContentPlaceHolder ID="main" runat="server"></asp:ContentPlaceHolder>
</form>
</body>
</html>
MainNavigation inherits from Root and contains the main menu and is commonly used for full-width pages and possibly the start page:
Default inherits from MainNavigation and adds elements such as sub-level menu (this is usually the most commonly used master page):
Define page types
I keep my page type definitions in a separate folder like so:
I’ll start with my Home page type for the start page so that I can move on with implementing the start page template:
Re-compile, refresh and we get the Home start page in the EPiServer UI:
Create the start page
First, create a new page under the Root folder node:
Note: If you’re unable to create a page under Root folder (the Create New option is disabled in the context menu), right-click the Root folder node, click Language Settings and then click Change beneath Available languages:
Once you’ve created your new start page, modify the <episerver> configuration element to set the pageStartId attribute to the page ID of the start page:
To find out the page ID of your start page, simply hover over it in the page tree:
Configuration changes
- Set <xhtmlConformance mode=”Strict”> in web.config (if using a strict doctype)
- Set the site ID and description in episerver.config (if you followed my tip on separating configuration files):
- Set the display name for the site within the <site> element:
- Disable AutoEventWireup in your template files…
…and override the OnLoad method instead of using Page_Load:
- Enable the HTTP cache by setting the httpCacheExpiration attribute of the <site> element in episerver.config:
Remove unused languages
Parsing and caching language files entails a performance hit on website startup. To reduce startup time, remove language files not being used.
Here’s my lang folder for an english / swedish website (site-specific translations are kept in the MyWebsite.xml file):