0% found this document useful (0 votes)
40 views47 pages

EpiServer JohannesRevisionNotes

Uploaded by

tsyovchev
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
40 views47 pages

EpiServer JohannesRevisionNotes

Uploaded by

tsyovchev
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 47

EpiServer

Reasons to avoid web forms:

1. Not supported by Episerver Forms


2. Episerver 12 will drop support
3. Commerce 12.1 dropped support in 2018

Nuget:
Install-Package <name> -ProjectName <project>
Update-Package <name> -ProjectName <project> -ToHighestMinor
Update-Package <name> -ProjectName <project> -Vesion <version>
Uninstall-Package <name> -ProjectName <project>

Database Updates
Update-EPiDatabase

or set updateDatabaseSchema="true" on <episerver.framework>

Customize TinyMCE
Dynamically change the behaviour - e.g. based on user roles:

[EditorDescriptorRegistration(TargetType = typeof(XhtmlString), EditorDescriptorBehav


ior = EditorDescriptorBehavior.PlaceLast)
public class TinyMceEditorDescriptor : EditorDescriptor
{
public override void ModifyMetadData(
ExtendedMetadata metadata,
IEnumerable<Attribute> attributes)
{
TinyMceSettings settings = metadata.EditorConfiguration["settings"] as TinyMceSet
tings;

settings
.AddSetting("table_toolbar", "tabledelete | tableinsertrowbefore")
.AddSetting("table_appearance_options", false);
}
}

or

Set defaults for the whole site or specific types:


[ModuleDependency(typeof(TinyMceInitialization))]
public class CustomizedTinyMceInitialization : IConfigurableModule
{
public void Initialize(InitializationEngine context) { }
public void Uninitialize(InitializationEngine context) { }

public void ConfigureContainer(ServiceConfigurationContext context)


{
context.Services.Configure<TinyMceConfiguration>(config =>
{
// default settings object ->
TinyMceSettings defaultSettings = config.Default();

// Load website CSS into TinyMCE


defaultSettings.ContentCss("/Static/css/site.css");

defaultSettings
.AddPlugin("table")
.AppendToolbar("table")

defaultSettings
.AppendToolbar("styleselect")
.StyleFormats(
new { title = "Red text", inline = "span", styles = new { color = "#ff0000"
} },
new { title = "Awesome numbering", selector = "ol", classes = "awesome-
numbering" },
new { title = "Roman numbering", selector = "ol", classes = "roman-
numbering" }
);

config.For<StandardPage>(t => t.MainBody)


.Toolbar("styleselect")
.StyleFormats(
new { title = "Bold text", inline = "strong" },
new { title = "Red text", inline = "span", styles = new { color = "#ff000
0" } },
new { title = "Red header", block = "h1", styles = new { color = "#ff0000
" } },
new { title = "button link", classes = "btn btn-
default", block="a", inline="span" }
);
});
}
}

Authorization and Authentication


When using federated authentication (e.g. ASP.NET Identity) the following changes are applied
to the web config as the configuration of this is done through an Owin startup module:
<authentication mode="none" />
<membership> is cleared
rolemanager is cleared

[assembly: OwinStartup(typeof(AlloyTemplates.Startup))]

namespace AlloyTemplates
{
public class Startup
{

public void Configuration(IAppBuilder app)


{

// Add CMS integration for ASP.NET Identity


app.AddCmsAspNetIdentity<ApplicationUser>();

// Remove to block registration of administrators


app.UseAdministratorRegistrationPage(() => HttpContext.Current.Request.Is
Local);

// Use cookie authentication


app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(Global.LoginPath),
Provider = new CookieAuthenticationProvider
{
// If the "/util/login.aspx" has been used for login otherwise yo
u don't need it you can remove OnApplyRedirect.
OnApplyRedirect = cookieApplyRedirectContext =>
{
app.CmsOnCookieApplyRedirect(cookieApplyRedirectContext, cook
ieApplyRedirectContext.OwinContext.Get<ApplicationSignInManager<ApplicationUser>>());
},

// Enables the application to validate the security stamp when th


e user logs in.
// This is a security feature which is used when you change a pas
sword or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<Ap
plicationUserManager<ApplicationUser>, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => manager.GenerateUserId
entityAsync(user))
}
});
}
}
}
Roles
CmsAdmins: (virtual) access to CMS admin section (not edit)
CmsEditors: (virtual) access to CMS edit and reports (not admin)
WebAdmins: default admin role.
VisitorGroupAdmins (virtual) access to visitor groups
EPiBetaUsers: (virtual) access to beta features.

Virtual Role Configuration

<episerver.framework>
<appData basePath="App_Data" />
<scanAssembly forceBinFolderScan="true" />
<virtualRoles addClaims="true">
<providers>
<add name="Administrators" type="EPiServer.Security.WindowsAdministratorsRole, EP
iServer.Framework" />
<add name="Everyone" type="EPiServer.Security.EveryoneRole, EPiServer.Framework"
/>
<add name="Authenticated" type="EPiServer.Security.AuthenticatedRole, EPiServer.F
ramework" />
<add name="Anonymous" type="EPiServer.Security.AnonymousRole, EPiServer.Framework
" />
<add name="CmsAdmins" type="EPiServer.Security.MappedRole, EPiServer.Framework" r
oles="WebAdmins, Administrators" mode="Any" />
<add name="CmsEditors" type="EPiServer.Security.MappedRole, EPiServer.Framework"
roles="WebEditors" mode="Any" />
<add name="Creator" type="EPiServer.Security.CreatorRole, EPiServer" />
</providers>
</virtualRoles>

Notes:

Prefer CmsAdmins over WebAdmins as it is more flexible.


Can specify per content type who can create.
Can disable inherit settings from parent item.
Can also apply settings to all subitems - adds additional; does not change or remove
existing.
When creating additional groups that require Episerver access; remember to update the
location elements in the web.config (prefer virtual roles though)

Permissions

Read
Create
Change
Delete
Publish
Administer

Permissions for Functions:

Allow users to move data/pages between page providers


Detailed error messages for troubleshooting
Allow the user to act as a web service user

<!-- episerver access -->


<location path="EPiServer">
<system.web>
...
<authorization>
<allow roles="WebEditors, WebAdmins, Administrators" />
<deny users="*" />
</authorization>
</system.web>
</location>

<!-- admin section -->


<location path="EPiServer/CMS/admin">
...
</location>

<location path="Views/Plugins">
...
</location>

APIs
UIRoleProvider

CreateRole(string role)
AddUserToRoles(string user, string[] roles)

UIUserProvider

CreateUser(string user, string password, string email)

PrincipalInfo
EPiServer.Security.PrincipalInfo.Current

Name: string
RoleList: string[]
(static) HasAdminAccess: bool
(static) HasEditAccess: bool
(static) HasPathAccess(string path): bool
(static) CurrentPrincipal: IPrincipal
(static) Current: PrincipalInfo
(static) CreatePrincipal(string username): IPrincipal

Personalization
Manual:

Individual: User Profiles


Segment: Visitor Groups

Automatic:

Episerver Content Recommendations: NLP-generated recs.


Episerver Content Intelligence: content analytics.
Episerver Visitor Intelligence: visualize journeys, define segments.
Episerver Customer Data Platform (CDP): imported from external.
Episerver Product Recommendations: on Commerce website.
Episerver Email Product Recommendations and Triggered Messages: e.g. abandoned
shopping cart.
Episerver Personalized Search & Navigation: boosted results.
Episerver Marketing Automation: omnichannel marketing email service provider (ESP).

Notes:

CDP: Customer data platform - A customer data platform is a marketer-managed system


that creates a persistent, unified customer database that is accessible to other systems.

Visitor Groups
Can be used in content areas and rich text areas

Can also personalize pages and media by removing the everyone access rights and adding a
visitor group with read access

Built-in Criteria

Number of visits
User Profile
Visited Category
Visited Page
Geographic Coordinate
Geographic Location
Time of day
Landing URL
Referrer
Search keyword
Visitor Group Membership

Note: Must setup a geolocation provider to have access to Geographic Coordinate and
Geographic Location criteria

<episerver.framework>
<geolocation defaultProvider="maxmind2">
<providers>
<add name="maxmind2"
type="EPiServer.Personalization.MaxMindGeolocationProvider,
EPiServer.Personalization.MaxMindGeolocation"
databaseFileName="App_Data\GeoLite2\GeoLite2-City.mmdb"
locationsFileName="App_Data\GeoLite2\GeoLite2-City-Locations-en.csv" />
</providers>
</geolocation>

Note: EPiServer.VisitorGroupsCriteriaPack adds additional visitor groups which can be used (e.g
IP address / OS / role etc)

User Profile
Episerver CMS includes a user profile feature that can be implemented by using the
EPiServerProfile class and
ASP.NET Profile configuration.

Projects
A project lets you manage the publishing process for multiple related content items.

Project feature is enabled for the entire site by default and appears as a dark gray bar at
the bottom of Edit view. Projects are activated by selecting their name from the popup list
of projects.
When a project is active, new or edited content is automatically added to the project.
When a project is not active, editing content shows its published version, not the draft in
the project. But a user can use the versions gadget to see the draft in the project and
switch to it.
The list of projects is visible to all users. Although a project cannot have access rights, all
the content items in a project could have access rights to prevent unauthorized users form
working with them.
You can publish items that are set to Ready to publish and leave items that are not ready
for a later time. You can continue working with a project even after some or all items are
published.
If a content item has been edited and published outside a project, then when the draft in
the project is published it becomes the published version. There is no merging.
Uploaded media that is associated with a project is not published until it is manually
published or published via scheduling, even if the automatic publish for media assets
setting is turned on.

Content Approval
When an editor has finished working on a content item, the item can only be set to Ready
for Review
At least one reviewer in each step must approve the content item before it is assigned a
status of Ready to Publish. Reviewers must have Read and at least one other access right to
approve or decline. Check boxes are available for comments and four-eyes enforcement
(e.g. cannot approve your own changes).
An approval sequence can be set up with any number of approval steps and any number of
reviewers in each step. The sequence is set up by an administrator, who also defined, for
each step individually, who can approve or decline a content item.
Assets, such as blocks and media (also forms and catalogues), cannot have individual
approval sequences. Instead, the content approval sequencne is set on each assets folder,
and all assets in a folder have the same approval sequence. The block and media folders in
the assets pane are actually the same folders in the software and share the same content
approval sequences.
It is recommended to have at least two reviewers per language and an administrator can
always approve and publish a page.
If content is in more than one language each language must have at least one reviewer.
Avoid large groups of reviewers as this can cause performance issues / spam / people to
assume someone else will deal with it.

Localization
To enable a language: CMS | Admin | Config | Manange Website Languages set language to
enabled and save.
Can specify which languages are available to edit a page in through the tools drop down
on a content item (tools -> language settings). Can still edit a previously published page
even if the language is no longer available.
CMS | Admin | Config | System Settings to enable "Detect language via browser's language
preference"
Episerver langauges addon can auto translate through Azure Translator (optional addon)
Thread.CurrentThread.CurrentCulture : must be a specific sub-culture as it affects date
formats and sort order (e.g. fr-CA)
Thread.CurrentThread.CurrentUICulture : can be netraul because it only affects loading of
localized strings (e.g. fr)
Can set the culture automatically in ASP.NET by setting culture="auto" uiCulture="auto"
on <globalization> in <system.web>
Strict language routing: urls (other than the root) must contain the language of the content
accessed.
Order of preference
System ( CurrentCulture ) and UI language ( CurrentUICulture ):

1. For anonymous visitors; content language.


2. For logged in users with a profile, user the personalized language selection for this user.
3. for the appropriate setting from web.config; if the culture is set to auto, the language
preferences from the web browser are used.

Content Language

1. If specified, use the language in the URL.


2. If you are in the Edit view and have a language selected for preview, that language is used.
3. If specified, use the language associated with a host name.
4. If it exists, use the language defined by the cookie named epslanguage.
5. If the Web.config setting pageUseBrowserLanguagePreferences is true, then the language
preference from the web browser is used.
6. Fetch the setting from the uiCulture attribute on <globalization> in Web.config.
7. If nothing else is discovered, use the first enabled language branch as defined in Admin |
Manage Website Languages , which means that it can be considered as the default language.

Fallback Language
if no content published for the specific language then this is used (can set up to two per
language)
Also used for nav - e.g. if fallback language content is available then items will be visible
(otherwise they won't show)
Trying to access a page by changing the language in url when the content doesn't exist in
the language or a fallback -> 404 (when using strict language routing)
If a content area does not have [CultureSpecific] then all blocks are shared between
languages; but only the blocks with a match published language (or a fallback) are shown.

Replacement Language
Outright replaces the languages; takes precedence over fallback.

Config

<localization fallbackBehavior="Echo, MissingMessage, FallbackCulture"


fallbackCulture="en">
<providers>
<add virtualPath="~/Resources/LanguageFiles" name="languageFiles"
type="EPiServer.Framework.Localization.XmlResources
.FileXmlLocalizationProvider, EPiServer.Framework.AspNet" />
</providers>
</localization>
Localizing content types
Note all files in this folder are read / included; the below are the default ones in Alloy.

~/Resources/Languagefiles

ContentTypesNames.xml (content types)

<productpage>
<name>Produkt</name>
<description>Används för att presentera en specifik produkt</description>
</productpage>

PropertyNames.xml (fields)

<?xml version="1.0" encoding="utf-8"?>


<languages>
<language name="English" id="en">
<contenttypes>
<icontentdata>
<properties>
<mainbody>
<caption>Main body</caption>
<help>Main editorial content of the page</help>
</mainbody>
<maincontentarea>
<caption>Large content area</caption>
</maincontentarea>
</properties>
</icontentdata>
</contenttypes>
</language>
</languages>

GroupNames.xml (tabs)

<?xml version="1.0" encoding="utf-8" ?>


<languages>
<language name="English" id="en">
<headings>
<heading name="Products">
<description>Products</description>
</heading>
<heading name="MetaData">
<description>SEO</description>
</heading>
</headings>
</language>
</languages>
Views.xml (cshtml)

<?xml version="1.0" encoding="utf-8" ?>


<languages>
<language name="English" id="en">
<contact>
<email>E-mail</email>
<phone>Phone</phone>
<noneselected>No contact selected</noneselected>
</contact>
</language>
</languages>

Usage
@Html.Translate("/productpage/changed")
LocalizationService:
GetString(string)
GetString(string, FallbackBehaviours)
TryGetString(string, out string)

Fallback Behavior
Echo
The key is returned unmodified if no match is found and the key is not a complex key
(starts with a '# or '/'). For complex key an empty value is returned when no match is found.
FallbackCulture
The resource is returned using the fallback culture if no match is found.
MissingMessage
A message saying that no resource was found is returned if no match is found.
Null
Returns null instead of an empty string when no match is found.

Content
Content Type: Defines a set of properties; can be associated with multiple content templates.
Content Item: Instance of a content type.
Content Flow:

Create -> Save -> Check-In (Ready to Publish) -> Publish -> Move to Trash -> Delete
|----------------------------------------^

Strongly Typed Models:


During site initialization all assemblies in the bin folder are scanned and all class types that
implement IContent are passed to the synchronization engine. The annotation information is
constructed by merging the annotated settings with the settings stored in the database using
the administrative interface. Any automatic properties on your content type class will reflect the
values of the backing PropertyData collection without the need of writing any code.

Last Updated Dates:

Modified: Only updated when the editor selects the "update modified date" checkbox.
Saved: last published date

There are two minimum requirements to define a type of content in Episerver:

Apply [ContentType] attribute and "implement" IContent

There are four main types of content built-in to Episerver CMS:

Page: an instance of a class that derives directly or indirectly from PageData


Folder: an instance of ContentFolder
Media: an instance of a class that derives directly or indirectly from MediaData or its
subclasses ImageData and VideoData
Block: an instance of a class that derives directly or indirectly from BlockData
Episerver Forms use FormContainerBase which inherits from BlockData so forms are
treated as a special type of block

ContentReference has three properties that uniquely identify an item of content:

ID : int
WorkID : int (aka version ID)
ProviderName : string ( null if default, or custom provider name)

Every IContent type has two link properties:

ContentLink : a reference to itself


ParentLink : a reference to its parent page/folder

Every PageData has two more link properties:

PageLink : a page reference to itself (deprecated)


ArchiveLink : a page reference to where to move to when the page expires

Custom properties must be public and virtual (unless [Ignore] 'd)


Defining Content Types

Pages

Inheritance: PageController<TPageData> -> ContentController<TPageData> ->


ActionControllerBase
[ContentType(DisplayName = "Start",
GroupName = SiteGroupNames.Specialized, Order = 10,
Description = "Desc",
GUID = "xxxx-xxxx-xxxx-xxxx",
AvailableInEditMode = true,
Order = 1)]
public class StartPage : PageData
{
[CultureSpecific]
[Display(Name = "Heading",
Description = "Desc",
GroupName = SystemTabNames.Content, Order = 10)]
public virtual string Heading { get; set; }

[CultureSpecific]
[Display(Name = "Main body",
Description = "Desc",
GroupName = SystemTabNames.Content, Order = 20)]
public virtual XhtmlString MainBody { get; set; }

[Display(Name = "Main content area",


Description = "Desc",
GroupName = SystemTabNames.Content, Order = 30)]
public virtual ContentArea MainContentArea { get; set; }
}

// Controller user to render the page directly:


public class StartPageController :
PageController<StartPage>
{
public StartPageController() { }

public Actionresult Index(StartPage currentPage)


{
return View(currentPage);
}
}

// Controller used to render the page in a content area:


public class ProductPagePartialController :
PartialContentController<ProductPage>
{
public override ActionResult Index(ProductPage currentPage)
{
// Partials do not have layouts - so layout page etc will be ignored.
return PartialView(currentPage);
}
}

Blocks

Inheritance: BlockController<TBlockData> -> PartialContentController<TBlockData> ->


ActionControllerBase

// Attribute takes the same arguments as the page example.


// Inherit from BlockData instead of PageData
[ContentType(...)]
public class MyBlock : BlockData
{
public virtual string MyString { get; set; }
}

public class BlockControllerSample : BlockController<MyBlock>


{
public override ActionResult Index(MyBlock blockData)
{
return PartialView(blockData);
}
}

Note: Can also create controller-less blocks by adding a MyBlock.cshtml file to ~/Views/Shared
which is supposedly more efficient...

Media

Inheritance:

ImageData -> MediaData -> ContentBase


VideoData -----^

[ContentType(DisplayName = "Image File",


Guid = "xxxx-xxxx-xxxx-xxxx",
Description = "Use this to upload image files.")]
// Specifies the file extensions this should be used for; if none specified gets used
as default.
[MediaDescriptor(ExtensionString = "png,gif,jpg,jpeg")]
public class ImageFile : ImageData
{
[CultureSpecific]
[Editable(true)]
public virtual string Description { get; set; }
}

public class ImageFileController : PartialContentController<ImageFile>


{
private readonly UrlResolver urlResolver;
public ImageFileController(UrlResolver urlResolver)
{
this.urlResolver = urlResolver;
}

public override ActionResult Index(ImageFile currentContent)


{
var model = new ImageViewModel
{
Url = urlResolver.GetUrl(currentContent.ContentLink),
Name = currentContent.Name,
Copyright = currentContent.Copyright
};
return PartialView(model);
}
}

Notes:

Types are set at creation; creating a type later does not convert existing instances (and no
tool exists for media; only for pages).
ImageData does not support SVG out of the box; can create custom (e.g. inherit and set
MediaDescriptor(ExtensionString = svg)
Folder structure is shared between blocks and media.
Can create a classname.cshtml to customize the default rendering (e.g. add a preview of an
image / pdf or similar)

Tabs

[GroupDefinitions]
public static class SiteTabNames
{
[Display(Order = 10)] // to sort horizontal tabs
[RequiredAccess(AccessLevel.Edit)]
public const string SEO = "SEO";

[Display(Order = 20)]
[RequiredAccess(AccessLevel.Administer)]
public const string SiteSettings = "Site Settings";
}

Notes:

Do not use PropertyFor for properties on "protected" tabs as apparently this bypasses
security...
The magic string "EPiServerCMS_SettingsPanel" will cause the property to go onto the top
panel rather than within the tabbed interface.
Class must be static

Customization

Override SetDefaultValues within a page / block to pre-populate fields with values.

Inheritance: PageReference -> ContentReference

Property Types:

ContentReference: Link to any IContent (e.g. block; media or page). Can limit input through
UIHints.
PageReference: Link to a page
ContentArea: Collections of IContent
It's possible to have a property of any block type; which will allow inline editing of a block
as part of the parent IContent item (but only a single instance).
Url: either an internal (page or media) or external link (url or email)
LinkItemCollection: multiple links
IList<ContentReference> : A list of references to content items.

Class Attributes:

AccessAttribute:
Users / Roles / VisitorGroups: specify which should have none; if none specified then
nobody will have access.
Access: content types only support Create.
Example: [Access(Users = "anfi", Roles="Site_Editors")]
AvailableContentTypesAttribute:
Availability: Defines whether all or no content types are available. If you set none,
other settings on the attribute is ignored. (None | All | Selected - optional)
Include: Array of types; specifies which content types can be created underneath this
type.
Exclude: Array of types; specifies which content types cannot be created underneath
this type.
IncludeOn: Array of types; specifies underneath which types this content type can be
created.
ExcludeOn: Array of types; specifies underneath which types this content type cannot
be created.
Types can be a (base) class or interface.
Example: [AvailableContentTypes(Exclude = new Type[] { typeof(X) })]
ImageUrl:
Path: the path to the icon to display.
TemplateDescriptor:
Controls which template to use render a block and / or page. Allowing a single content
item to have multiple ways of rendering.
Inherited: When set to true, model types that inherit from the ModelType get the
template as a supported template.
Default: Defines the template as the default template for the model type.
Description: Description of the template
ModelType: The model for the content type. This can be set for untyped templates
which derives from EPiServer.TemplatePage to set the model type, which is the type of
the CurrentPage property.
Path: The path to the rendering template
AvailableWithoutTag: Template will be available when no tags are set.
Tags: Template will be used when any of these tags are set (e.g. @Html.PropertyFor(x
=> x, new { Tag = "x" }))
Example: [TemplateDescriptor(Inherited = true, Tags = new[] { SiteTags.Full },
AvailableWithoutTag = true

Notes:

Changes made in the CMS to these properties will take priority over those set by code; can
reset the CMS changes through the "Revert to default" button on the type
RenderingTags.Preview and RenderingTags.Edit can be used together with a
TemplateDescriptor to create a custom preview controller to render previews for multiple
DisplayOptions

[TemplateDescriptor(Inherited = true,
TemplateTypeCategory = TemplateTypeCategories.MvcController,
Tags = new[] { RenderingTags.Preview, RenderingTags.Edit },
AvailableWithoutTag =false)]
public class PreviewController : ActionControllerBase, IRenderTemplate<BlockData>
{
public ActionResult Index(IContent currentContent)
{
// Start page is used in the below as the default Alloy templates require a C
urrentPage.
var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
var startPage = contentLoader.Get<PageData>(ContentReference.StartPage);
var model = new BlockEditPageViewModel(startPage, currentContent);

return View(model);
}
}

Automatically applying tags

public class MobileDisplayChannel : DisplayChannel


{
public override string ChannelName => RenderingTags.Mobile;

public override bool IsActive(HttpContextBase context)


{
return context.Request.Browser.IsMobileDevice;
}
}

Notes:

Implement IDisplayResolution to extend the resolution dropdown visible in Episerver


when previewing a channel.
A DisplayChannel can only have a single default IDisplayResolution although others can
manually be selected.

Property Attributes:

UIHint
Controls the UI to render for the property within Episerver.
UIHint.Block | UIHint.BlockFolder | UIHint.Image | UIHint.Legacy |
UIHint.LongString | UIHint.MediaFile | UIHint.MediaFolder |
UIHint.PreviewableText | UIHint.TextArea | UIHint.Video
Example: [UIHint(UIHint.Image)]
StringLength
Example: [StringLength(60, MinimumLength = 5)]
SelectOne / SelectMany
Allows the selection of values through either a dropdown or checkboxes. The factory type
must implement ISelectionFactory
Example: [SelectOne(SelectionFactoryType=typeof(LanguageSelectionFactory))]
Required
AllowedTypes
Specifies which content types are allowed within a ContentArea
Example: [AllowTypes(typeof(BlockA), typeof(BlockB))]
Restricted types are passed through as a second array of types:
[AllowedTypes(typeof(BlockData), new[] { typeof(JumbotronBlock) })]
ScaffoldColumn
Hides the property from the content editor
Searchable
Includes the property in the search index
Editable
Whether the property is editable through the UI
ListItems
Specifies the minimum and / or maximum allowed items within a list
Example: [ListItem(1, 2, ErrorMessage("Specify between 1 and 2 items"))]
Ignore
Stops the value from being stored in the database
Various other MVC validation attributes Range , RegularExpression , Compare etc...

APIs
FilterAccess:

Filter( PageDataCollection pages): void


Filters out pages that do not fulfill the AccessLevel criteria passed to the constructor.

FilterPublished:

Filter( PageDataCollection pages): void


Filters out pages that do not fulfill the PublishedStatus criteria passed to the constructor.

FilterForVisitor:

(static) Filter( PageDataCollection pages): PageDataCollection


Filters out any pages that should not be shown to the current user (unpublished or
permissions)

IContentLoader:

Read-only access to Epi database


IContentRepository:

Full CRUD access to Epi database

ContentReference.GlobalBlockFolder global folder shared between all sites.


ContentReference.SiteBlockFolder shared blocks that are site specific.

Selection Factory

public class ThemeSelectionFactory : ISelectionFactory


{
public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata)
{
yield return new SelectItem { Value = "theme1", Text = "Orange" };
yield return new SelectItem { Value = "theme2", Text = "Purple" };
yield return new SelectItem { Value = "theme3", Text = "Green" };
}
}

Initialization Modules

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class RegisterAdminInitializationModule : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
// context.Locate.Advanced.GetInstance<TType>();
}

public void Uninitialize(InitializationEngine context)


{

}
}

Dependency Injection

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class RegisterDependencyResolverInitializationModule : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
DependencyResolver.SetResolver(new StructureMapDependencyResolver(context.Structu
reMap()));
//Implementations for custom interfaces can be registered here.
context.ConfigurationComplete += (o, e) =>
{
context.Services.AddTransient<IService, Service>();
//Register custom implementations that should be used in favour of the default
implementations
};
}
public void Initialize(InitializationEngine context) { }
public void Uninitialize(InitializationEngine context) { }
}

Display Options
Customize the list of options shown when using the urger menu on an item in a content area ->
display as.

Customize the rendering through the EditorDescriptor and the associated tags below.

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class DisplayOptionsInitializationModule : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
var options = context.Locate.Advanced.GetInstance<DisplayOptions>();

options.Add(id: SiteTags.Full, name: "Full", tag: SiteTags.Full);


options.Add(id: SiteTags.Wide, name: "Wide", tag: SiteTags.Wide);
options.Add(id: SiteTags.Narrow, name: "Narrow", tag: SiteTags.Narrow);
}

public void Uninitialize(InitializationEngine context) { }


}

Events

[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class PreventMoreThanMaxChildrenInitializationModule : IInitializableModule
{
private bool initialized = false;
private IContentEvents events;
private IContentLoader loader;
private const int maxChildren = 8;

public void Initialize(InitializationEngine context)


{
if (!initialized)
{
loader = context.Locate.ContentLoader();
events = context.Locate.ContentEvents();

events.CreatingContent += Events_CreatingContent;
initialized = true;
}
}

private void Events_CreatingContent(object sender, ContentEventArgs e)


{
var sitepage = e.Content as SitePageData;

if (sitepage != null)
{
var children = loader.GetChildren<IContent>(sitepage.ParentLink);
if (children.Count() >= maxChildren)
{
e.CancelAction = true;
e.CancelReason = $"Cannot create a new page if the parent has {maxChildren} o
r more children.";
}
}
}

public void Uninitialize(InitializationEngine context)


{
if (initialized)
{
events.CreatingContent -= Events_CreatingContent;
}
}
}

Scheduled Jobs

[ScheduledPlugIn(DisplayName = "Test Job", Description = "Test Job.")]


public class TestScheduledJob : ScheduledJobBase
{
private bool _stopSignaled;

public TestScheduledJob()
{
IsStoppable = true;
}

public override void Stop()


{
_stopSignaled = true;
}

public override string Execute()


{
OnStatusChanged(string.Format("Starting execution of {0}", this.GetType()));

// Do stuff.

//For long running jobs periodically check if stop is signaled and if so stop exe
cution
if (_stopSignaled)
{
return "Stop of job was called";
}

return "done";
}
}
Caching

Output Caching

Response.Cache.SetCacheability(System.Web.HttpCacheability.Public);
Response.Cache.SetExpires(System.DateTime.Now.AddHours(1));
Response.Cache.SetSlidingExpiration(true);

Alternatively:

[EPiServer.Web.Mvc.ContentOutputCache]
public ViewResult Index(SitePageData currentPage)

Notes:

Output caching only caches for anonymous users.


Static files are done through the web.config

<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00" />
</staticContent>
<system.webServer>

Object Caching
TODO

Logging
Levels:

Trace
Debug
Information (Because why would you want to type just Info; I think Episerver wants to sell
keyboards or something)
Warning (Warn would have clearly been ambiguous)
Error
Critical (Fuck standards; who has ever heard of Log4Net, NLog and Serilog)
private readonly ILogger logger = LogManager.GetLogger();

logger.Error("msg");
Logger.Error("msg", exception);
logger.Error("{0}, {1}", 1, 2);
logger.Error(item, s => "msg: " + s.Expensive());
logger.Error(item, exception, (s, ex) => "msg:" + s.Expensive() + " ex: " + ex.Messag
e);

Episerver Forms
Form definitions are stored as content in the CMS, in a similar way to blocks, so they can be
treated as content.
Form submissions are stored in Dynamic Data Store by default.
Form elements are included like t Text and Selection. Developers can define their own by
deriving from ElementBlockBase .
Use forms primarily when an editor will do the form management; use a page type for
complex forms requiring custom business logic.
Can use Azure Keyvault to encrypt the form submissions; default is plain text.
Retention policy can differ between in-progress and finalized default 30 days for in-
progress; 90 for finalized. But can specify both days and forever.

Page Shortcuts
No shortcut: Creates a link that displays the content you have created. By selecting this,
you can also reset
the page after using other types of links.
Shortcut to another content item: A visitor who clicks this link will be transferred to the
page or media
asset you have selected and kept within the same navigation menu structure.
Shortcut to page on another website: Creates a link to an external URL. The resource could
be anything.
You must specify the absolute URL address, for example, including "https://"
No shortcut, display text only: Creates a heading with no link in the menu, without
displaying any
information or link to another page.
Fetch content from another content item: Creates a link to the original page but any
empty property values
on that page will be fetched from the referenced page or media asset. Useful when re-
using content on the
website because you only need to maintain it in one place.

DXC
Addons not supported on DXC:

Search
CMO
Mail
Relate

Reporting
1. Not Published Pages
2. Published Pages
3. Changed Pages
4. Expired Pages
5. Simple Addresses
6. Link Status (requires the Link Validation scheduled job to be executed.)

Change Log
The following events are registered within the Change Log:

Check In
Publish
Delete
Save
Move
Create
Delete Language
Delete Children
Deleted Items
Rejected
Delayed Publish
Request Approval

Misc Helpers

@Html.DisplayFor(x => x)

@Html.PropertyFor(x => x)
@Html.Propertyfor(x => x, additionalViewData: new { CssClass = "row", Color = "pink"
})
(retrieve from ViewContext.ParentActionViewContext.ViewData)

@Html.EditAttributes(x => x)
@Url.Content("~/Static/css/file.css")
@Url.ContentUrl(ContentLink)
@Html.ContentLink(ContentLink)
@Html.CanonicalLink()
@Html.AlternateLinks()
@Html.RenderEPiServerQuickNavigator()
@Html.MenuList(ContentLink, @<div>@Html.PageLink(item.Page</div>)
PageEditing.PageIsInEditMode
@RenderBody()
@RenderSection()

CurrentPage.HasTemplate()

// render content item using partial template (e.g. page in block layout)
@Html.RenderContentData(someContent, isContentInContentArea: false)

// Refresh entire page when property is modified


@Html.FullRefreshPropertiesMetaData(new[] { "ShowBanner" })

Notes:

Render tags (used for EditorDescriptor ) can be passed as part of the anonymous class
for PropertyFor and the like.

Episerver Labs

Block Enhancements
Features:

Inline block editing;


Show block status on content area;
Inline publishing;
Content draft view
Smart Publish

A/B Testing
Notes:

Can set participation percentage; test duration (days); when to start; and whether to
published the winning version automatically.

Conversion Goals:

Landing Page - the chosen page is one that a user must click on in order to count as a
conversion.
Site Stickiness - converts when a user visits the content under test and then visits any other
page within the same browser session.
Time on page: monitors how long a visitor spends on a page and converts after a specified
amount of time.

Self-Optimizing Block
You can add multiple child blocks inside and only a single instance is shown (e.g. chance is
1 / count)
Automatically adjusts over time to show the block that earns the most conversions more
often than the other block variants. For example the best of four blocks might be shown 37
times out of 100.
Can have only a single conversion goal; and only works with blocks.

Search Provider: Order can be set through admin UI

Multiplexing: provider 1 must be writable to support user management.

Asset Pane: Blocks, Media and Forms tabs. Expandable form elements and archived tests.
If you need more complex validation, for example that the value of one property should be
validated
depending on the value of another property, then you can implement
EPiServer.Validation.IValidate<T> (where
T is the type to validate). No registration is needed, the initialization scanning will register all
implementations
automatically.

The validator will be called during Save for each content instance that can be assigned to T.
Note however
that this validation will be done on server side only.
CMS 11 IList<T> aka PropertyList only officially supports simple types like int and DateTime.
It can be used with complex types but this is not officially supported (yet).
SearchHandler = Epi Search
SearchClient = Epi Find
https://world.episerver.com/documentation/developer-guides/content-delivery-api/

https://mmols.io/
getting-started-with-the-episerver-content-delivery-api/
!!!!

GuiPlugIn
Component
BackingType

You might also like