The following example demonstrates how to create a basic custom module, including all steps required to create Installation packages for the module. You can use the packages to distribute the module to other instances of Xperience. The sample module provides a "Company overview" that allows management of custom Office objects.
Important:
It is necessary to follow all of the sections below in the presented order. Skipping steps may prevent subsequent sections from working correctly.
Start by defining the module in the Xperience administration interface:
The system automatically uses CompanyOverview as the Module code name.
Module code names
Carefully consider the code name when creating custom modules. The name is used to identify the module's folders, files and DLL within the web project, as well as in the code names of related Xperience objects (web parts, form controls, etc.). Choose a sufficiently unique module code name to avoid collisions with the default Xperience modules or other custom modules.
Do NOT start the code names of custom modules with the cms. prefix, which is reserved for Xperience system modules.
Read and Modify are standard permissions that the system checks automatically for various purposes, including access of the module's user interface and editing of the module's objects.
We recommend defining the Read and Modify permissions for all custom modules that have their own user interface and data. Without the permissions, only users with the Global administrator privilege level can edit objects that belong to the module.
To allow the creation of Installation packages for the module, you need to integrate a new web application project into your Xperience solution.
Add the CompanyOverview project to your Xperience administration solution:
Open your Xperience solution in Visual Studio (using the WebApp.sln file).
In the Solution Explorer, right-click the solution and choose Add -> Existing Project.
Select CompanyOverview.csproj in the project's CMS folder.
Add the required references between the projects:
Expand the Properties folder of the CompanyOverview project and edit CompanyOverviewAssemblyInfo.cs.
Add the AssemblyDiscoverable assembly attribute:
using CMS;
[assembly:AssemblyDiscoverable]Save the solution and all files.
The Xperience solution now contains a web application project representing the Company overview custom module. The additional project will only exist on the Xperience instance that you use to develop the module. When you install the module on a different instance, all code is already compiled inside the module's DLL and other files are integrated into the main Xperience project.
Module classes represent objects in Xperience. The classes serve as containers for configuration such as data fields, editing form definitions, and search settings. Classes also have associated code that provides an API for manipulating the given object.
To create a custom class for the sample module:
In the Xperience administration interface, open the Modules application and edit the Company overview module.
Select the Classes tab.
Click New class.
Fill in the Class display name and Class: Office
Click Next.
In step 2, leave the default values and click Next.
Notice the Include Guid field and Include LastModified field checkboxes. If selected, the system automatically creates data fields for storing GUID identifiers and last modified timestamps. These two fields are necessary if you wish to use Staging or Export and Import functionality with objects of the given class.
See also: Enabling export and staging for the data of classes
Define the class's data fields. Click New field, set the properties, and click Save for each field:
Click Next once the required fields are defined.
Click Finish to complete the creation of the class.
The system automatically creates a database table for storing the class's data.
The system provides a tool for automatically generating the basic code required for the API of the custom class:
Switch to the Code tab of the class.
The required system fields should automatically be mapped to the corresponding fields of the class (Display name, Code name, GUID, Last modified).
Change the Save path to: ~/CompanyOverview
Click Save code. The system generates Info, IInfoProvider and InfoProvider classes for the custom class.
Open the Xperience solution in Visual Studio and include the new files into the module's project:
Build the CompanyOverview project.
The default generated classes are sufficient for basic functionality, but you can extend the code to create an API for your custom class. To learn how to set the metadata of your classes in the Info code, see Setting the type information for module classes.
Start by preparing a resource file (.resx) for the custom module:
The resource file allows you to create resource strings for your custom module. Add a string for displaying the Office class's object type name:
The system uses the resource string in the administration interface, for example when selecting object types.
You can use the Portal Engine to develop custom pages in the administration interface for your modules. The portal engine allows you to perform most of the work directly in your browser, and build UI elements out of page templates and web parts.
The following sections describe how to create a basic editing interface for the Office objects used by the sample Company overview module.
In the Modules application, edit the Company overview module.
Open the User interface tab.
Select the CMS -> Administration -> Custom element in the tree.
Click New element ().
Set the following properties for the element:
Click Save.
The UI element's position in the user interface tree under the CMS -> Administration -> (Category) section identifies the new element as an application.
By default, the element only checks the Read permission of the related module, and does not have any other access restrictions. For more information about the settings of UI elements, see Reference - Managing UI elements.
The purpose of the element is to display a list of all Office objects in the system. You need to set the properties of the Object listing page template for the UI element:
Every listing page requires an XML grid definition, specified by the Grid definition path property. With the property empty, the system attempts to load the grid definition from the default location for the given module and object type.
For the purposes of the example, create the default.xml file in the following location:
~/App_Data/CMSModules/CompanyOverview/UI/Grids/CompanyOverview_Office/default.xml
<?xml version="1.0" encoding="utf-8" ?>
<grid>
<actions>
<action name="edit" caption="$General.Edit$" fonticonclass="icon-edit" fonticonstyle="allow" />
<action name="#delete" caption="$General.Delete$" fonticonclass="icon-bin" fonticonstyle="critical" confirmation="$General.ConfirmDelete$" />
</actions>
<columns>
<column source="OfficeDisplayName" caption="Office name" wrap="false" localize="true">
<filter type="text" size="200" />
</column>
<column source="OfficeAddress" caption="Address" width="100%" />
</columns>
<options>
<key name="DisplayFilter" value="true" />
</options>
</grid>The Object listing template uses the Xperience UniGrid control. To learn how to create XML definitions for object lists, see Reference - UniGrid definition.
The example above defines two basic actions for the listed objects:
Select Company overview in the UI element tree.
Click New element ().
Set the following properties for the element:
Click Save.
The New element allows users to create new offices from the listing page. If you switch to the Properties tab, you can see that the element automatically inherits the Object type from the parent listing page (Custom office).
Select Company overview in the UI element tree.
Click New element ().
Set the following properties for the element:
Click Save.
The Edit element provides the editing form used when editing offices on the listing page.
If you switch to the Properties tab you can see that the element automatically inherits the Object type from the parent listing page (Custom office).
Tip: For complex objects, you can build an editing interface with multiple tabs:
The tabs element automatically generates a tab menu for the child elements. You can find an example on the Creating custom binding classes page.
The user interface of the custom module is now ready. If you refresh the administration interface header, you can find the Company overview application in the Custom category. The application displays a listing page, where you can create, edit and delete offices. Users who do not have the Global administrator privilege level can only access the list if they have the Read permission for the Company overview module, and create, edit and delete offices if they have the Modify permission.
You can register your custom module and execute code during its initialization if you need the module to modify the behavior of the Xperience application. This approach is recommended when developing customizations directly related to the module*.*
Open your project in Visual Studio.
Create a new class in the module's code folder (the CompanyOverview folder under the CompanyOverview project for the sample module).
Make the module class inherit from CMS.DataEngine.Module.
Define the constructor of the module class:
Register the module class using the RegisterModule assembly attribute.
Implement your custom functionality inside the module class.
Save the class file and Build the module's project.
You can achieve most customizations by running code during the initialization of the module – override the following methods:
Because you cannot manually set the initialization order of modules or define dependencies between modules, we do not recommend working with the data of other modules directly inside the OnInit method*.* The best approach is to assign handlers to system events, and perform the actual operations inside the handler methods. For general code that is not related to a specific system event, you can use the ApplicationEvents.Initialized.Execute event, which occurs after all modules in the system are initialized.
For example, the following code extends the sample Company overview module. The example uses event handling to log an entry in the system's Event log whenever a new office is created.
Library references
You need to add references to your module project for any Xperience libraries required by your custom code. For example, the sample code below requires an additional references to the CMS.EventLog and CMS.Core libraries:
using CMS;
using CMS.Core;
using CMS.DataEngine;
using CMS.EventLog;
using CompanyOverview;
[assembly: RegisterModule(typeof(CompanyOverviewModule))]
namespace CompanyOverview
{
public class CompanyOverviewModule : Module
{
// Module class constructor, inherits from the base constructor
// Uses the code name of the module as the first parameter
// Sets the isInstallable parameter to true, ensures that the module's initialization runs only after its database objects are installed
public CompanyOverviewModule() : base("CompanyOverview", true)
{
}
/// <summary>
/// Initializes the module. Called when the application starts.
/// </summary>
protected override void OnInit()
{
base.OnInit();
// Assigns a handler to the Insert.After event for OfficeInfo objects
CompanyOverview.OfficeInfo.TYPEINFO.Events.Insert.After += Office_InsertAfter;
}
private void Office_InsertAfter(object sender, ObjectEventArgs e)
{
// Logs an information entry into the system's event log whenever a new office is created
string message = "New office '" + e.Object.GetStringValue("OfficeDisplayName", "") + "' was created in the Company overview module.";
Service.Resolve<IEventLogService>().LogInformation("Company overview module", "NEW OFFICE", message);
}
}
}You can transfer the custom module to other instances of Xperience by creating installation packages. Edit the module in the Modules application and click Create installation package on the General tab. The resulting package contains the module's database objects and files, with all code compiled into a DLL.
When the package is installed on another instance of Xperience, the module automatically becomes sealed and is no longer in development mode (i.e. it is not possible to edit the module's properties, or create new classes, UI elements, permissions and settings). If you view the target instance's solution in Visual Studio, the module's web application project is not present – all code is already compiled inside the module's DLL and other files are integrated into the main Xperience project.
Note: You cannot create installation packages for the module again on instances where it is sealed. You always need to prepare the module package on the original instance where the module is in development mode.