Oct 13

Written by: Bruce Chapman
Monday, October 13, 2008 10:26 AM 

I answered a post on the DNN Forum the other day relating to a question about how to go about structuring a custom build DotNetNuke® module. It's an area probably covered well in various DNN books, but I think it's a question that most experienced developers but first-time DNN module builders ask. Here's how I recommend you structure and build your custom DNN modules.

DotNetNuke modules are generally a package of ASP.NET User Controls, plus some application code. The most popular way of building and distributing modules is in a Private Assembly (PA) package, bundled into an installable Zip file. Most of the third-party modules are distributed in this manner - the iFinity modules are all done like this.

This post is going to cover the why and how of designing and structuring your DNN modules. It doesn't cover the ways of writing your module or packaging and distributing the module.

A Module is not a Module

The first problem at hand with understanding DNN module structure is the heavily overloaded term 'Module'. A 'DNN Module' in the popular sense of the word means all of the following things:

  • A Zip package that you install using the module installer.
  • An entry in the list on the 'Module Definitions' page.
  • An item in the list of installable modules in the DotNetNuke control panel.
  • An instance on a DNN Page that is generally used to edit and display content.

For the end-user of a DNN site, it matters little that 'module' covers all of these definitions. We think of the 'Text/Html Module' as being all of the above, and for end users, it's an accurate enough depiction to get through the process of installing and using the module.

However, for a developer of a module, it's not nearly accurate enough, because all these things are different, and when you're trying to design and architect a module, you need to know the difference. It's a bit like database queries, stored procedures, views and tables. To an end user, they all produce a list of data, but to the developer, there's a world of difference in how each is physically created and designed.

Note : In case you didn't already know, a 'Tab' is a DNN Page. So Page == Tab. The origins of the definition 'Tab' go back to the IBuySpy workshop, the original code distributed by Microsoft which DNN grew from. The IBuySpyWorkshop used a 'tab control' interface, so Tabs == Pages.

More accurate descriptions of Module Parts

To eliminate confusion, I'm going to define some more accurate terms to cover the different parts. These are a little bit outside official DNN Terminology, but I'll stick as close as I can to the correct terms.

  • A zip package that you install : A Module Install Package
  • An entry in the list on the 'Module Definitions' page : A Desktop Module (it's confusing, I know)
  • An item in the list of installable modules in the DotNetNuke control panel : A User Desktop Module (UDM)*
  • An instance on a DNN Page that is generally used to edit and display content : A Tab Module

* Note that 'UMD' is my terminology. Not all Module Definitions are installable : you can't install, say, a File Manager Module Definition, even though it clearly exists as one in the DNN tables. This is because it's an 'Admin' module that can't be installed. DNN actually needs a 'UAMD' or 'User Admin Module Definition', which would be a class of module where you can add it to a Tab, but it's not part of the DNN Admin modules.

And I'm going to add some more for the developer to understand:

  • A logical group of controls which, when added to a page, create a Tab Module instance : A Module Definition
  • An ASP.NET User Control (.ascx file) which is displayed when a UMD is added to a DNN Tab : A Module Control
  • A Business Controller : A public class (.NET Type) in the module code which can be called by the DNN Framework.
  • A Settings Control : An ASP.NET User Control, which can be loaded into the 'Module Settings' page, accessible on a Tab Module 'Settings' menu command.

With these terms defined, we can discuss choices on structuring a module correctly.

Designing a Module Structure

There's no one answer about how to build a module the correct way. I've seen a lot of core and third party modules, and they seem to all follow a different path to achieve the end result. That's the beauty of the DNN platform in a way : you can really go off on some different tangents and it will all hang together.

If you've just got a simple module with one 'view' control, one 'edit' control and one 'settings' control, it's pretty simple : you just create the three separate user controls, package it up and install. This is the design for most of the simple modules, like the 'Text/Html', 'Announcements' and 'Links' modules.

But there are really two main paths to DNN module structure, and I'll call these 'all in one' and 'separate parts'.

The 'all in one' structure is where all of the Module Controls for a module are combined into a single Module Definition. Remember, a Module Definition is what you see in the drop down list in the Control Panel. Most simple modules like the 'Text/Html' module are all-in-one, principally because there's not much to it.

More complex 'all in one' examples are the Blog module, which, as anyone who has ever installed it knows, drops about 6 actual Tab Modules onto your chosen Tab when you click 'add module'. At first this is confusing, but it's easy enough to configure by moving the Tab Modules around and deleting the ones you do not need.

The 'separate parts' model is where each individual control is in it's own module definition. When you install a module package for a design like this, you end up with a set of module definitions in your list. A couple of examples in the third-party market that I know of include the CataLOOK store and the Simple Gallery module from Ventrian.

There's no correct answer as to which to choose : each has benefits and drawbacks.

All In One

The 'all in one' design has simplicity on it's side: instead of being presented with a series of 20 character names for the module definitions, you just have one. End users will know what to click to install your module. However, when you end up with 4 or 5 different Tab Modules on the Tab, it's hard as an end-user to know what to do.

I would recommend this design when you have a module with only a couple of different Module Controls, and when those Module controls are reasonably related in terms of use. Taking the blog example, it makes sense : if you're installing a blog on page, the archive, entries and search functions are all related. If you're creating an e-commerce package, then having the shop, cart, checkout and account controls on the one page doesn't make as much sense.

Separate Parts

You would normally use this when there are relatively unrelated parts to a module package, or perhaps when you would expect different Module Definitions to be added on different Tabs. An example might be a summary module of Blog Entries : it wouldn't normally live on the same Tab as the entries themselves, so you would probably create a separate Module Definition for the Summary and Main articles.

The advantage of this approach is that the user can install the different definitions to different tabs, integrating the functionality into their site they way they see fit. The disadvantage is that, unless you're careful with naming and documentation, it's not always obvious how to achieve a working setup.

The 'Blob'

The Blob is a subset of the 'All in One' approach. This is where there is only one module definition, and when added to a page, only one Tab Module. But the module has a series of different functions - but all those functions are just different representations of the same page. Examples of this are the DNN Forums : There's only one module definition, and it just puts a single Tab Module on the page. But that Tab Module has myriads of different functions - but you can't spread the module across separate Tabs in the site. WIth the forums module, you can't have a post add/edit on one page, and a post view on another. It works well with Forums, but this model needs to be chosen with care.

Choosing Between the Design Styles

My advice when choosing between the design styles is to consider what your finished page/site will look like. Do you want the user to be able to shift different parts of your module around their portals, or is it important that everything is restricted to a single DNN Tab? Are all the functions homogenous to the module, or does the module do various things.

In general terms, something like an e-commerce module has many functions, including search functions, product lists, product details, shopping carts, checkout pages and user-specific information like order details. In a design like this, it's probably better to break down the overall functionality into module definitions along the functional (or destination Tab, if it helps) lines:

  • Product Listings
  • Product Search
  • Shopping Cart
  • User Account

A design like this pretty much matches what you would expect to see in a list of Tabs on the site. But it would also allow flexibility for, say, having different DNN Tabs for different product categories. Allowing users to place different instances of essentially the same Tab Module gives them the flexibility to do things like have different skins for each page, as well as place complementary DNN modules on separate pages. Consider an e-commerce site that sold baby products. With an e-commerce module that allows you to have different Tab Modules of the same Module Control, you could have a site structure like this:

mybabyproducts.com
-->products
-->-->boys
-->-->girls
-->checkout
-->my orders

This allows the end user to apply a pink skin to the girls page and a blue skin to the boys page, and save you, the module developer, from having to build complex module-based skinning code. But you must allow the different Tab Module instances to filter the displayed content by some type of Tab Module Setting.

However, if you're building a module that does something where there are a couple of modules, and they are all closely related, then it makes sense to go with the 'all-in-one' style. The Blog module is a good example of this, as already discussed. You don't have separate Tabs for 'entries', 'archive', 'search' on a blog - it all just goes on the one page.

Implementing your Design Style

After the design style is chosen, then you're at the point of actually writing some code. It helps if you actually start with the 'Manifest' file, otherwise known as the '.dnn' file. This is an Xml file which actually contains the structure of your module. It gets placed in the 'desktopModules' folder of your module as a .dnn.config file, so you can look at any particular example you like.

The way you structure this file controls the installation and architecture of your module.

Translating Design with the Manifest File

The below image depicts the manifest file for the Blog module. The various areas are highlighted and point to what effect the manifest file contents will have on the Desktop Module once it is installed.

DNN Manifest File Breakout

As you can see, the Blog module has a single folder defined for the entire install package. This is the 'all in one' approach I have already described. There is a 1:1 relationship between the Module Definition and the Folder in the Manifest file. Each <folder> entry will create two things: a new folder in the /DesktopModules/ folder, and a new Desktop Module in the Module Definitions page. Remember, the 'Module Definitions' page should actually be called the 'Desktop Modules' page.

Within each <folder> there are one or more <module> entries. Each one of these relates to a Module Definition, which, from above, is a logical grouping of controls. Each Tab Module will be an instance of the contents of a <module> entry.

If you wish to create more than one DestkopModule (which, in turn, creates more than one entry on the 'Module Definitions' screen, then you need to define an extra <folder> entry, and provide all the same details.

It's worth studying this image and getting a solid understanding of how all the parts go together, because you will need to author your own Manifest files if you are to become a proficient DNN module developer. I realise it is confusing : if it wasn't, there would be no need for this blog entry.

Designing the Module Controls

There's three basic types of Module Controls:

  • 'View' controls : these are the 'default' view of the module which all authorised users get to see
  • 'Edit' controls : these are only visible when (a) the user is authorised to edit the module and (b) when the site is in 'Edit' mode.
  • 'Settings' controls : these are loaded along with the standard DNN module settings, and also are only visible when the site is in 'Edit' mode and the user is authorised.

Most module definitions contain one module control with no <key> value. This is the default control loaded when the DNN Tab with the Tab Module on it is viewed. In the case of the 'Text/Html' module, that's just the Html of the page. In the case of the Blog Module, that's the 'MainView' control, which shows the list of latest entries.

View Control

The above image shows that there are no module-specific Url parameters for the DNN Tab. The blog Tab Module on the page is therefore showing the control which has no <key> specified : the 'View_Blog' control.

Edit Control

This image shows an Edit control for the Blog Module. Note that in the DNN Manifest file for the Blog Module, it doesn't use a <key> value of 'Edit', rather it shows a key value of 'Edit_Entry'. This is because, with the Blog module, there is more than one type of Edit control within the overall definitions. This is a good lesson to take away: if your module will have more than one type of edit screen, it's a good idea to break down the different type of edit screen in the module keys. The highlighted Url in the image shows /ctl/Edit_Entry/mid/381/EntryId/47/, which will be rewritten into a querystring of ctl=Edit_Entry&mid=381&EntryId=47. This Url would have been generated by the 'EditUrl()' function call. The 'EditUrl' call returns the Url for a specific module control : it differs from the 'NavigateUrl' call in this way.

The difference is (and this is important) that the 'mid=381' value is added. In DNN, whenever you add a 'mid=xxx' specifier to the query string, it will still show the DNN Tab, it will only load the specified module. That is to say, will only load the module on the tab where the moduleId = 399 (or whatever your module Id is).

A popular design trend amongst modules is to put a 'control panel' into the module, and AJAX the living daylights out of it. Whilst this can produce a nice-looking control-panel style, in my experience it also produces bloated, slow pages. You're much better off defining a different control for each function in your control panel, and definining them all with different <key> values.

For an example : let's imagine your module will have an 'edit' function, which will contain these three different groups of functionality:

  • Widgets
  • Wigwams
  • Doodads

Instead of creating a single module control with all three sections in some type of multi-panel AJAX control, you can define three separate 'Edit' controls, with specific module keys.

<controls>
    <control>
      <key>Edit_Widgets</key>
      <title>Edit Widgets</title>
      <src>EditWidgets.ascx</src>
      <type>Edit</type>
    </control>
    <control>
      <key>Edit_Wigwams</key>
      <title>Edit Wigwams</title>
      <src>Wigwams.ascx</src>
      <type>Edit</type>
    </control>
    <control>
      <key>Edit_Doodads</key>
      <title>Edit Doodads</title>
      <src>Doodads.ascx</src>
      <type>Edit</type>
    </control>

Note : You might think the edit control Urls aren't SEO-Friendly, and you'd be right. It doesn't matter because search engines should never be indexing edit content, and users should never bookmark it.

Settings Control

The last thing I want to cover is the 'Settings' control. The 'settings' control is a special type of DNN Module Control, and it inherits from a different base (PortalSettingsBase). The Settings control has a different <type> value - 'Settings'. This means it will be loaded in the DNN Tab brought up when you click on the 'Settings' icon in the DNN module. This link will always load up the standard DNN settings, which has values for security, appearance etc. You can add the Tab Module specific settings to the bottom of this page, and add your own custom settings.

Again, this is controlled by the Url - as you can see in the above image. Only this time, the <key> value is set for you - it's always /ctl/Module.

The important thing to remember here is that the 'Settings' page allows you to save tab-module specific settings. This mightn't sound like much of a difference, but DNN provides you with a 'Settings' hashtable to store simple key/value settings for your module. DNN also provides the user the ability to copy any module onto one or more pages - and then change the settings individually for each of those Tab Module instances. By storing custom values in the TabModuleSettings hashtable, you can have different options for each Tab Module instance, even when all those Tab Module instances were copied from somewhere in the site.

Summary of Module Design

DNN Module design can be as simple or as complicated as you need. But when you stray into more complex module designs, it's worth sketching out how your module is going to fit together.

Here's key questions you need to answer before you start coding:

  • Will the module content be displayed on a single 'view', or are there multiple facets to what the module will display?
  • If there are multiple facets, are they tightly coupled and likely to all be shown on the one Tab, or are they likely to be spread through the site? The answer to this will drive your choice between an 'all in one' design or a 'separate parts' style.
  • How many edit screens will you need? Will you split them out into separate controls, or combine the edit functionality into one control? You must consider things like viewstate size when attempting to combine many controls onto a single page, especially when trying to AJAX everything up.
  • What options and settings should be saved at the 'entire-module' level, and what should be saved at the 'Tab Module' level? Can you add settings like content-filters, that allow an end-user to spread the same module across different pages but filter for specific content? The example mentioned was an e-commerce product list that allowed for filtering between different categories, allowing the end user to build different Urls through placement of Product listings on different pages, and to use different theming by applying DNN skins/containers to specific pages.

Of course, all of this discussion just scratches the surface of the DNN Module Design process, but hopefully it gives food for thought about building robust, flexible and speedy DNN modules.

Tags:

4 comment(s) so far...

Re: Designing, Structuring and Architecting DotNetNuke® Modules

"In DNN, whenever you add a 'mid=xxx' specifier to the query string, it will still show the DNN Tab, it will only load the specified module. That is to say, will only load the module on the tab where the moduleId = 399 (or whatever your module Id is)"

Are the mids awarded to DesktopModules or Module Definitions. i.e. do all Module definitions in Blog module have separate mids??

By Rahul Singla on   Saturday, November 15, 2008 4:33 PM

Re: Designing, Structuring and Architecting DotNetNuke® Modules

No, the 'mid' (or 'ModuleId') is the ModuleId value on the Modules table. There is one instance in the Module table for each Module instance in your site - basically one ModuleId for each time you click 'add' on your control panel. Note that each Module record can have one or many TabModule records.

By Bruce Chapman on   Sunday, November 16, 2008 8:01 AM

Re: Designing, Structuring and Architecting DotNetNuke® Modules

That essentially means that all TabModules produced on dropping a Blog instance on a tab share the same ModuleId, but have different TabModuleIds.

So, does that also mean that if I move these Tab Modules generated from a single Control Panel "Add" click (which you also call Module Definitions) to separate pages, they would still share the ModuleId while retaining their divergent TabModuleIds.
Am I correct??

By Rahul Singla on   Sunday, November 16, 2008 2:55 PM

Re: Designing, Structuring and Architecting DotNetNuke® Modules

Rahul,

Not quite correct. When a module is listed in the drop down list - it's uniquely identified by the DesktopModuleId, which comes from the section of the DNN Manifest file. When you click 'Add', a new Module record is created for each section in the manifest file, each of which is represented by a module definition record. So with each 'add' you may create more than one Module Id, because there can be more than one Module Definition.

The blog module has about 5 modules that get created from the one DesktopModule record. Each of these get assigned a unique module Id.

If you shift this instance to a different tab, you maintain the same TabModuleId, it's just the 'TabId' value that gets updated.

By Bruce Chapman on   Monday, November 17, 2008 7:20 AM

Your name:
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Add Comment   Cancel 
Need Help?
 

If you're having trouble with an iFinity Product, use the Support Forums to search for answers, and to post questions.

If you need help faster than that, or can't figure out the answer, try our Premium Support service.