+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Creating Sitefinity 4 Content Modules Part 5: Module Installation

by Josh Morales

Table of Contents

This series covering Sitefinity Content-Based Module creation is broken up into 5 parts:

Overview

In the last four posts in this series, we laid the foundation and connected all the plumbing for our module. Now that everything is in place, the only thing left to do is complete the module class, registering and initializing the module and its associated controls and pages.

This is done by filling in the methods we created in part 1, and we'll take a look at each method and what it does separately. Once again, the completed project will be available for download (and the complete solution including a sample website) will be distributed in the Sitefinity SDK.

Initialize

This method registers both the module configuration (LocationsConfig) as well as the backend web service we defined in part 3. Update it with the following code.

/// Initializes the service with specified settings.
/// </summary>
/// <param name="settings">The settings.</param>
public override void Initialize(ModuleSettings settings)
{
    base.Initialize(settings);

    // initialize configuration file
    Config.RegisterSection<LocationsConfig>();

    // register web services
    ObjectFactory.RegisterWebService(typeof(LocationsBackendService), "Sitefinity/Services/Content/Locations.svc");
}

Install

This method simply adds the Locations Module to the list of Sitefinity Modules.

/// <summary>
/// Installs this module in Sitefinity system for the first time.
/// </summary>
/// <param name="initializer">The Site Initializer. A helper class for installing Sitefinity modules.</param>
public override void Install(SiteInitializer initializer)
{
    base.Install(initializer);

    // register module ?
    IModule locationsModule;
    SystemManager.ApplicationModules.TryGetValue(LocationsModule.ModuleName, out locationsModule);

    initializer.Context.SaveMetaData(true);
}

InstallPages

This is the key to module installation. As we saw in part 1, this method is where the actual module installation takes place, creating the backend pages and registering the backend administration we created in part 3. Refer to part 1 for a detailed walkthrough the method then update the method with this code.

/// <summary>
/// Installs the pages.
/// </summary>
/// <param name="initializer">The initializer.</param>
protected override void InstallPages(SiteInitializer initializer)
{
    // code to install admin page nodes and pages
    // get pagemanager
    var pageManager = initializer.PageManager;
    var modulesPageNode = pageManager.GetPageNode(SiteInitializer.ModulesNodeId);

    // Create PageNode if doesn't exist
    var locationsModulePageGroupNode = pageManager.GetPageNodes().Where(t => t.Id == LocationsPageGroupID).SingleOrDefault();
    if (locationsModulePageGroupNode == null)
    {
        // create page node under Modules node
        locationsModulePageGroupNode = initializer.CreatePageNode(LocationsPageGroupID, modulesPageNode, Telerik.Sitefinity.Pages.Model.NodeType.Group);
        locationsModulePageGroupNode.Name = LocationsModule.ModuleName;
        locationsModulePageGroupNode.ShowInNavigation = true;
        locationsModulePageGroupNode.Attributes["ModuleName"] = LocationsModule.ModuleName;

        // hard-code names for now, will eventually be localized
        locationsModulePageGroupNode.Title = "Locations";
        locationsModulePageGroupNode.UrlName = "Locations";
        locationsModulePageGroupNode.Description = "Module for managing a list of Locations";
    }

    // create Landing Page if doesn't exist
    var landingPage = pageManager.GetPageNodes().SingleOrDefault(p => p.Id == LandingPageId);
    if (landingPage == null)
    {
        // create page
        var pageInfo = new PageDataElement()
        {
            PageId = LandingPageId,
            IncludeScriptManager = true,
            ShowInNavigation = false,
            EnableViewState = false,
            TemplateName = SiteInitializer.BackendTemplateName,

            // hard-code names for now, will eventually be localized
            Name = LocationsModule.ModuleName,
            MenuName = "Locations Module",
            UrlName = "Locations",
            Description = "Landing page for the Locations Module",
            HtmlTitle = "Locations Module"
        };

        pageInfo.Parameters["ModuleName"] = LocationsModule.ModuleName;

        // create control panel
        var backendView = new BackendContentView()
        {
            ModuleName = LocationsModule.ModuleName,
            ControlDefinitionName = LocationsDefinitions.BackendDefinitionName
        };

        // add page
        initializer.CreatePageFromConfiguration(pageInfo, locationsModulePageGroupNode, backendView);
    }
}

Upgrade

This method is not used, as we are not performing any upgrades to the module. You can leave it blank for now.

InstallTaxonomies

Here we simply register our LocationItem type into the Sitefinity taxonomy system. Use the following code.

/// <summary>
/// Registers the module data item type into the taxnomy system
/// </summary>
/// <param name="initializer">The initializer.</param>
protected override void InstallTaxonomies(SiteInitializer initializer)
{
    this.InstallTaxonomy(initializer, typeof(LocationItem));
}

GetModuleConfig

This is simply a helper method to simplify retrieval of the module configuration.

/// <summary>
/// Gets the module config.
/// </summary>
/// <returns></returns>
protected override ConfigSection GetModuleConfig()
{
    // code to return Module configuration
    return Config.Get<LocationsConfig>();
}

InstallConfiguration

The other major component of any module is the frontend public controls. This method registers the LocationsView control in the Toolbox so users can drag and drop it onto a page.

/// <summary>
/// Installs module's toolbox configuration.
/// </summary>
/// <param name="initializer">The initializer.</param>
protected override void InstallConfiguration(SiteInitializer initializer)
{
    // get section from toolbox
    var config = initializer.Context.GetConfig<ToolboxesConfig>();
    var pageControls = config.Toolboxes["PageControls"];
    var section = pageControls
        .Sections
        .Where<ToolboxSection>(e => e.Name == ToolboxesConfig.ContentToolboxSectionName)
        .FirstOrDefault();

    // create it if it doesn't exist
    if (section == null)
    {
        section = new ToolboxSection(pageControls.Sections)
        {
            Name = ToolboxesConfig.ContentToolboxSectionName,
            Title = "ContentToolboxSectionTitle",
            Description = "ContentToolboxSectionDescription",
            ResourceClassId = typeof(PageResources).Name
        };
        pageControls.Sections.Add(section);
    }

    // add locations view if it doesn't exist
    if (!section.Tools.Any<ToolboxItem>(e => e.Name == "LocationsView"))
    {
        var tool = new ToolboxItem(section.Tools)
        {
            Name = "LocationsView",
            Title = "Locations View",
            Description = "Public control from the Locations module",
            CssClass = "sfLocationsViewIcn",
            ControlType = typeof(LocationsView).AssemblyQualifiedName
        };
        section.Tools.Add(tool);
    }
}

Public Properties and Constants

Finally, we have a few properties to override, namely the LandingPageId (backed by a private constant) and the Managers, which retrieves the Content Manager for the module. Finish out the module class with the following code.

 #region Public Properties

        /// <summary>
        /// Gets the landing page id for each module inherit from <see cref="T:Telerik.Sitefinity.Services.SecuredModuleBase"/> class.
        /// </summary>
        /// <value>
        /// The landing page id.
        /// </value>
        public override Guid LandingPageId
        {
            get { return LocationsModuleLandingPage; }
        }

        public override Type[] Managers
        {
            get { return new[] { typeof(LocationsManager) }; }
        }

        #endregion


        #region Constants

        /// <summary>
        /// The name of the Locations Module
        /// </summary>
        public const string ModuleName = "Locations";

        // Page IDs
        public static readonly Guid LocationsPageGroupID = new Guid("000262BF-E8EA-4BE3-8C67-E1C2486A57BE");
        public static readonly Guid LocationsModuleLandingPage = new Guid("7A0F43CE-064A-4E09-A3B9-59CA2E1640A6");

        #endregion

Virtual Path Provider Registration

Recall that in the previous step on building the frontend controls for our module, we set a path to their templates using the Virtual Path Provider.

In order for our module to be able to load these virtual paths, they need to be registered during module installation. Otherwise you will get see “error parsing the template” when you add the public control to a page.

Add the following method to the LocationsModule class:

private void InstallCustomVirtualPaths(SiteInitializer initializer)
{
    var virtualPathConfig = initializer.Context.GetConfig<VirtualPathSettingsConfig>();
    ConfigManager.Executed += new EventHandler<ExecutedEventArgs>(ConfigManager_Executed);
    var locationsModuleVirtualPathConfig = new VirtualPathElement(virtualPathConfig.VirtualPaths)
    {
        VirtualPath = "~/LocationTemplates/*",
        ResolverName = "EmbeddedResourceResolver",
        ResourceLocation = "LocationsModule"
    };
    if (!virtualPathConfig.VirtualPaths.ContainsKey("~/LocationTemplates/*"))
        virtualPathConfig.VirtualPaths.Add(locationsModuleVirtualPathConfig);
}

Then simply call the method from the Install method of the module:

public override void Install(SiteInitializer initializer)
{
    base.Install(initializer);

    // register module ?
    IModule locationsModule;
    SystemManager.ApplicationModules.TryGetValue(LocationsModule.ModuleName, out locationsModule);

    initializer.Context.SaveMetaData(true);
    this.InstallCustomVirtualPaths(initializer);
}

 

Installation

We covered module installation in the "Hello, World" example from part 1 of this series, so here is a summary of the required steps.

  1. Login to the Sitefinity backend
  2. Navigate to Administration > Settings > Advanced Settings
  3. Expand System > ApplicationModules node
  4. Click "Create New"
  5. Add module details; Leave Version blank; Set Startup type to "OnApplicationStart"
  6. Save Changes
  7. Restart your website by saving your site web.config file

Once you've completed installation, you can now go to the Locations module page in the backend, as well as drop the LocationsView onto a Sitefinity page.

Sitefinity-4-Locations-Custom-Module Sitefinity-4-Custom-Locations-Module

With that, the module is complete! The completed module is available for download below, and will also be available in the Q2 release of the SDK.

What's Next

We've now built and installed a complete Sitefinity Content-Based Module. It has all the BASIC components in place, but there is still much more we can do to make our module more complete.

This will be explored further in a continuing series of follow-up Advanced Topic posts, covering everything from adding control designers to the LocationsView control to supporting security, content lifecycle and workflow.

Be sure to share your experience with this module in our Sitefinity 4 SDK Discussion Forum as well as any comments, questions, or suggestions for future posts on module creation.

Downloads

14 comments

Leave a comment
  1. Euclid Public Library Jul 25, 2011
    I downloaded the "Completed Locations Module" and attempted to install it in to an existing Sitefinity website following the provided instructions.  Everything works except the "Locations View" front end control.  I get the following error while in the page designer and nothing when in published view.  Note that the control designer for the "Locations View" is working normally. 

    Error Message --> "Error parsing the template"

    Please advise.
  2. Josh Jul 25, 2011
    Make sure that you have followed the instructions for registering the Virtual Path Provider in your site's Global.asax file. The intsructions are above on this page.

    I am looking into a better way to do this so this step is not necessary, but rather is registered when the module installs. Thank you for your feedback!
  3. NewToSitefinity Jul 31, 2011
    Added the code to the Global.asax and still get the Error parsing message. What else can I try?
  4. Josh Aug 01, 2011
    Make sure that the path you've registered and the path you configured in the detailsview and masterlist view are the same.

    I'll take a look at the project this week and see if I've missed anything and report back.
  5. NewToSitefinity Aug 01, 2011
    Added the code to the Global.asax and still get the Error parsing message. What else can I try?
  6. NewToSitefinity Aug 01, 2011
    Ok will take a look and let you know. Thanks!
  7. NewToSitefinity Aug 01, 2011
    You were right.
    The VirtualPath in the Bootstrapper_Initializing method needed to be
    VirtualPath = "~/Locations/*"

    Thanks for the post, it was really helpful. Looking forward to the followup on implementing workflow and security
  8. Josh Aug 12, 2011
    The blog post has been modified to reflect placing the VPP registration in the module itself, so that you don't have to modify the global.asax file.

    The download in the blog post still has the old way (global.asax) but for an updated example, be sure to download the Sitefinity SDK as it has the complete working module.
  9. Shital Sep 02, 2011
    Hey Josh, I didn't get "Locations View" widgets. Can you point me any place where I might have made mistake?
  10. Josh Sep 07, 2011
    @Shital did the module install completely, that is do you see the Locations menu item in the backend? If the module installation fails, all the changes are rolled back, including the widget registration.

    You can also check the Error log in the App_Data folder for a logged exception related to the widget registration.

    Additionally, check the ToolboxesConfig.config file and see if your widgets are registered and that the types are correct (namespace, spelling, etc).

    If you continue to experience issues, please open up a thread on the Sitefinity SDK forum so we can continue troubleshooting the project together.
  11. poker3 May 06, 2013
    онлайн покер на деньги cheat engine, азартные игры онлайн без регистрации 777 [url=http://kazino5.igry-slot-avtomaty.ru/new4544.html]игровой клуб рио днепропетровск[/url] скачать карточные игры мобильного lg [url=http://kazino5.igry-slot-avtomaty.ru/new2128.html]игровые автоматы играть бесплатно карты 1000[/url]
  12. Phuc Ngo May 27, 2013
    I downloaded the "Completed Locations Module" and attempted to install it  on Sitefinity website following the provided instructions.  When I view it. it saw the error 

    Server Error in '/' Application.

    Object reference not set to an instance of an object.



    Description: An unhandled exception occurred during
    the execution of the current web request. Please review the stack trace
    for more information about the error and where it originated in the
    code.





    Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.



    Source Error:








    An unhandled exception was generated during the execution of the current
    web request. Information regarding the origin and location of the
    exception can be identified using the exception stack trace below.








    Stack Trace:






    [NullReferenceException: Object reference not set to an instance of an object.]
    Telerik.Sitefinity.Web.UI.ContentUI.ContentViewControlDefinition.GetDefaultMasterView() +122
    Telerik.Sitefinity.Web.UI.ContentUI.ContentView.DetermineCurrentViewName() +572
    Telerik.Sitefinity.Web.UI.ContentUI.ContentView.CreateChildControls() +104
    System.Web.UI.Control.EnsureChildControls() +171
    System.Web.UI.Control.PreRenderRecursiveInternal() +138
    System.Web.UI.Control.PreRenderRecursiveInternal() +337
    System.Web.UI.Control.PreRenderRecursiveInternal() +337
    System.Web.UI.Control.PreRenderRecursiveInternal() +337
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5042


    Please give me a advise . I install it on i sitefinity 6.0 with trial version


    Thanks
  13. Phuc Ngo May 27, 2013
    I downloaded the "Completed Locations Module" and attempted to install it  on Sitefinity website following the provided instructions.  When I view it. it saw the error 

    Server Error in '/' Application.

    Object reference not set to an instance of an object.



    Description: An unhandled exception occurred during
    the execution of the current web request. Please review the stack trace
    for more information about the error and where it originated in the
    code.





    Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.



    Source Error:








    An unhandled exception was generated during the execution of the current
    web request. Information regarding the origin and location of the
    exception can be identified using the exception stack trace below.








    Stack Trace:






    [NullReferenceException: Object reference not set to an instance of an object.]
    Telerik.Sitefinity.Web.UI.ContentUI.ContentViewControlDefinition.GetDefaultMasterView() +122
    Telerik.Sitefinity.Web.UI.ContentUI.ContentView.DetermineCurrentViewName() +572
    Telerik.Sitefinity.Web.UI.ContentUI.ContentView.CreateChildControls() +104
    System.Web.UI.Control.EnsureChildControls() +171
    System.Web.UI.Control.PreRenderRecursiveInternal() +138
    System.Web.UI.Control.PreRenderRecursiveInternal() +337
    System.Web.UI.Control.PreRenderRecursiveInternal() +337
    System.Web.UI.Control.PreRenderRecursiveInternal() +337
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5042


    Please give me a advise . I install it on i sitefinity 6.0 with trial version


    Thanks
  14. Rohit Kumar Pathak Sep 17, 2014

    Hello,

    What are the differences between a module's Install and Initialize methods ?


    Leave a comment