November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
The Add-ons Store shipped with the EPiServer, allows site administrators to view and install add-ons to EPiServer websites. It is also possible to install and manage the add-ons from Visual Studio but allow site administrators to get read-only view to add-ons, see Installing Add-ons for details. Add-on modules can be developed both by EPiServer as well as third-parties. This document describes how to develop your own add-ons as well as how add-ons are handled on a website.
An add-on can contain components that extend the functionality of the EPiServer website, like initializable modules, gadgets, visitor group criteria, virtual path providers, page and search providers.
Add-ons are packaged as ordinary NuGet packages and follows a defined set of guidelines. The folder structure and configuration system used by add-ons are defined by the module system. The module system, or Shell modules, is a built-in module system primarily to extend the user interface but can be used to build any module.
Below is a set of guidelines to consider when developing add-ons.
// MapDynamicContent is type from add-on assembly:
string pathToControl = Paths.ToResource(typeof(MapDynamicContent), "Map.ascx");
// load control using resolved path:
page.LoadControl(pathToControl);
string pathToAddonScript = Paths.ToClientResource(typeof(MapDynamicContent), "ClientResources/MapContent.js");// register client script using resolved path:
Page.ClientScript.RegisterClientScriptInclude("MapContent.js", pathToAddonScript);
An EPiServer add-on is delivered as a NuGet package, containing all add-on resources and assemblies. A package can be created from an assembly, a project or a convention-based working directory. Refer to the tools and documentation available from Nuget, for information on how to create a NuGet package.
Run the following command to create a NuGet manifest (nuspec) file for your add-on package:
nuget spec
Edit the nuspec file you just created, and specify the information appropriate for your add-on package. If you are going to create your package from a project, you can use replacement tokens for the add-on package ID, version, author and description. The following nuspec file example is for the Google Maps add-on:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>$id$</id>
<version>$version$</version>
<title>Google Maps dynamic content</title>
<authors>$author$</authors>
<owners />
<iconUrl>http://world.episerver.com/PageFiles/3/Icons/Nuget.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Allows to add Google Maps as dynamic content on pages.</description>
<tags>EPiServerPublicModulePackage Google Maps Dynamic</tags>
<dependencies>
<dependency id="EPiServer.Samples.SampleFoundation" version="1.2" />
<dependency id="EPiServer.CMS.UI" version="7.5" />
</dependencies>
</metadata>
</package>
The difference between public and protected add-ons lies in the user access rights required to access the add-on files/routes.
Public and protected add-ons have the following file locations and virtual paths:
If your add-on requires other add-ons to be installed on the site, you can add these to the list of dependencies in the nuspec file. Doing so will ensure that if these other add-ons are not already installed when a user chooses to install yours, the other add-ons will also be installed if possible. If the other add-ons are not possible to install to the environment, the installation will abort.
Add-on packages must follow the Semantic Versioning (SemVer) scheme for versioning for the package itself, in order to have a common understanding of which versions will be compatible and which can introduce breaking changes.
SemVer means having version numbers in the format Major.Minor.Patch, where the different segments correspond to:
If we for example require the feature set from version 1.3 of a dependency, we can simply set "[1.3,2)" as the version range. This will accept all versions that are known to be compatible. When version 2.0 is released it may or may not turn out to be compatible for our purposes. If it is compatible, the version range can be changed to "[1.3,3)" in the next update. Otherwise the version range, once our codebase has been changed to run with version 2.0 of this dependency, will be changed to something like "[2.0,3)".
Refer to NuGet Docs for more information about version ranges in NuGet.
Prerequisites are dependencies to installed products that are not installed as actual add-on packages. These dependencies serve to limit the possibility to install packages that require specific products to ensure compatibility. For this purpose, assemblies installed in the application as well as system packages (e.g. EPiServer.CMS.Core and EPiServer.CMS.UI) are represented in the NuGet environment as virtual packages that one can add dependencies to. The names and version numbers of these packages are based on the assembly names and assembly versions. Note that for Visual Studio enabled add-ons the dependencies must be actual NuGet packages.
The package directory structure should follow the conventions in NuGet Docs for more details on how to create packages.
If you are going to create the package from a Visual Studio project, run the following:
nuget pack AddOnProject.csproj
Alternatively, if you have prepared a NuGet manifest (nuspec) file and a convention based directory structure for the actual package content, you can create the package as follows:
nuget.exe pack addondirectory\addon.nuspec
Another option is to use the NuGet Package Explorer GUI tool to view metadata and create new packages.
Below is an example of the Sample Google Maps add-on package opened in NuGet Package Explorer.
All dependencies should be to ordinary NuGet packages rather than just references to assemblies, in most scenarios the primary assembly of the NuGet package matches the ID of the package.
All content files must have a path in the nuspec as they appear on site. This implies that paths for content files should include "\modules\<packageid>" for public add-ons, for example:
<file src="Settings.aspx" target="Content\modules\<packageId>\Settings.aspx" />
and "modules\_protected\<packageid>" for protected add-ons, for example:
<file src="Views\Setting\Index.aspx" target="Content\modules\_protected\<packageId>\Views\Setting\Index.aspx" />
The NuGet package should contain a module.config file in the package root (e.g. <file src="module.config" target="Content\modules\<packageId>\module.config" />). The module config must contain an attribute 'tags' that contain either EPiServerModulePackage or EPiServerPublicModulePackage. This is required for the EPiServer add-on UI to be able to distinguish the add-on from other shell modules. The module config can also contain a 'description' attribute that will describe the module in the add-on UI. It should also list all assemblies the package contains of. A minimial module.config example is given below:
<?xml version="1.0" encoding="utf-8"?>
<module loadFromBin="false" description="Allows to run various support tools on the site." tags=" EPiServerModulePackage ">
<assemblies>
<add assembly="DeveloperTools" />
</assemblies>
</module>
It's recommended to deliver all content in your add-on as a compressed ZIP archive. One of the main benitifs of this approach is that developers that adds a reference to your package does not get a lot of files, for instance views and JavaScript files, included in their project. Simply compress the whole content structure below the package folder to a zip file and give it the same name as your the package itself and place within the package directory, for example:
Content\modules\<packageId>\<packageId>.zip
EPiServer will scan all module directories during startup and add a virtual path provider for any archive that is found as long as it follows this convention.
Using this feature is NOT recommended if your module contains large files as the content will be kept in a memory cache. It can however be useful if you are developing a Visual Studio add-on that contains a vast amount of small files as it will prevent the module from adding all those files to the Visual Studio project of the developers installing your add-on. If you want to debug files in an add-on that uses this functionality, simply extract the archive into it's current directory and delete/rename the archive.
Custom code can be executed at the following extension points, when certain actions will be performed:
If your add-on only requires to execute custom code on web application start-up and does not need to be notified about installations, updates or deletions, consider using IInitializableModule.
In order to get custom code executed when the status of the add-on package changes, it should include a class inherited from the abstract class EPiServer.Packaging.PackageInitializer in the EPiServer.Packaging assembly:
public abstract class PackageInitializer : IInitializableModule, IPackageNotification
{
#region Implementation of IInitializableModule
public virtual void ConfigureContainer(ServiceConfigurationContext context);
public virtual void Initialize(InitializationEngine context);
public virtual void Uninitialize(InitializationEngine context);
public virtual void Preload(string[] parameters);
#endregion
#region Implementation of IPackageNotification
public abstract void AfterInstall();
public abstract void AfterUpdate();
public abstract void BeforeUninstall();
#endregion
}
The PackageInitializer class combines the IInitializableModule and IPackageNotification interfaces. Inheritors of this class are instantiated and executed by the EPiServer Framework initialization system in the same manner as for the regular IInitializableModule.
The Initialize method in PackageInitializer checks if the add-on (package ID) containing the assembly with the inheriting class is newly installed, and calls the AfterInstall method if necessary, or if the add-on is newly updated calls AfterUpdate if necessary.
When overriding the Initialize method, you should call the base implementation before proceeding with the initialization to ensure that the AfterInstall and AfterUpdate methods are executed before the initialization.
The BeforeUninstall method is called before the package contents are removed, when the user clicks the Uninstall button in the add-on system.
This contains the code to be executed after the add-on installation is complete. This method is called only the first time the application starts after the add-on installation, as opposed to the Initialize method which is called each time the application starts.
Do the following to get custom code executed after an add-on installation:
The add-on installation and the point where the AfterInstall method is called:
Code executed after the add-on update is complete, this method is called only the first time the application starts after updating an add-on.
Do the following to execute custom code after an add-on update:
The add-on installation and the point where the AfterUpdate method is called:
This method is executed immediately after the user clicks the Uninstall button in the add-on management user interface, but before the actual uninstallation takes place. If an exception is thrown in the BeforeUninstall method, the uninstallation will be aborted. Does not trigger when uninstalling an add-on using Visual Studio.
Do the following to execute custom code before add-on unistallation:
The process of add-on uninstallation:
If an add-on is dependent on other systems or add-ons, it needs to indicate these dependencies using ModuleDependency attributes. This way the initialization methods will be called after those of all of the listed dependencies.
Last updated: Jul 09, 2014