November 2007 Entries

What is View Limiter? Watch the demo.

Today I want to show you a small module I created a few weeks ago. My module is called View Limiter, and it allow you to put constraints on how many pages a user can view in a set timeframe. Once you setup an instance of View Limiter, messages are sent through the inter-module communication mechanism telling all the other modules that a page view limit has been reached (or not reached). Modules that listen for messages from a View Limiter get the notification that a limit has been reached, and can use this information in any way they want (e.g. display alternative content or an error message).

Screen-cast This!

Today I am also experimenting with screen-cast technology. I can't express how incredibly painful it currently is to embed flash movies into a subtext post. Ideally I would like to use swfobject to do all the work for me in an accessible and compliant manner. But subtext is pretty much limiting me to only using the generic embed method. I hope Subtext "Poseidon" is coming out soon so we can all lend a hand in adding the desperately needed functionality to subtext using its upcoming plug-in framework.

Anyway, I apologize for any ear-bleeding or motion-sickness you might experience while watching the screen-cast above. I promise to kill the mouse-click sounds next time! Please give me your feedback regarding the View Limiter module! Thanks for reading!

Welcome Back! Last time I showed you how you can programmatically create pages from your module: Programmatically Creating DotNetNuke Pages. Today I want to show you how to programmatically add and remove module instances to and from pages in your DotNetNuke site.

The DotNetNuke.Entities.Modules Namespace

The DotNetNuke.Entities.Modules namespace brings to the party all the needed functionality required for adding and removing module instances to and from pages. When you explore this namespace you are going to find a whole lot more than you bargained for. For instance the DesktopModuleInfo, DesktopModuleController, and ModuleDefinitionInfo classes are all living in this namespace. Many of these classes are what DotNetNuke uses to represent and manage all the types of modules that are installed in your site.

The classes we are interested in today are the ModuleInfo and ModuleController classes. These two classes represent and manage instances of the module definitions.

DotNetNuke.Entities.Modules.ModuleInfo

The ModuleInfo class represents an instance of a module in DotNetNuke. You might recall that one module “instance” can exist on multiple pages, however these “instances” that live on multiple pages do not correspond one-to-one with unique instances of the ModuleInfo class. In the database there is a Modules table and a TabModules table. For every “instance” of a module on your site, there is an entry in the Modules table. For every page that a particular “instance” exists on, there is an entry in the TabModules table. Generally speaking, a ModuleInfo instance is associated with a particular TabModules table entry, meaning its key in the database consists of a combination of both the ModuleId and the TabId.

The information inside a ModuleInfo object actually contains a complex amalgamate of information that I don’t really care to explain in detail at this point. Suffice it to say that DotNetNuke pulls all the required information into the object for you using the vw_Modules view:

image

How fun is that!? One could probably write a small book about this relationship alone! I’m just not up for it today.

So anyway, there is no need to be intimidated by this view because the DotNetNuke Framework does all the heavy-lifting for you through the next class we are going to talk about.

DotNetNuke.Entities.Modules.ModuleController

The ModuleController class is basically a gift from the DotNetNuke Gods. This class will add, copy, delete, retrieve, and update module instances for you in no less than 10,000 ways. (Don’t hold me to that, I barely received a B in my 400-level stats course)

image

The ModuleController class’ methods are listed above. One of these methods will likely do what you need.

Adding a New Module Instance

The basic method for programmatically creating a new module instance in your site is as follows:

1. First create an instance of the ModuleController class

2. Then create an instance of the ModuleInfo class

3. Populate the properties of the ModuleInfo instance

4. Pass the ModuleInfo instance to the AddModule() method of the ModuleController object

This looks simple, but don’t fool yourself. Step 3, populating the properties, can be a lot of work! The best starting point for figuring out how to populate these properties is to dig into the DotNetNuke source code to take a look at the ControlPanelBase.vb file. The ControlPanelBase class has a protected method named AddNewModule() that goes through the painful work of populating all the properties of a ModuleInfo class. This is a ton of code, so I won’t be posting it here. You can download the source from here.

After you have the ModuleInfo object populated with information, you simply pass the object to the AddModule() method of the controller object.

Public Function AddModule(ByVal objModule As ModuleInfo) As Integer

AddModule() takes a ModuleInfo object that represents your new module instance, and it returns the id of the new module in the database.

Copying a Module Instance

Sometimes you want a modules instance to live on several different pages. In order to achieve this effect you must first acquire the id of the module that you wish to have on several pages. You must also build an ArrayList of TabInfo objects that represent each of the pages that you wish to have your module exist on. Once you have this information ready you call the CopyModule() method of the ModuleController class to copy the module to all the pages you specified in the ArrayList you created.

ModuleController.CopyModule() has the following signature:

Public Sub CopyModule(ByVal moduleId As Integer, _

   ByVal fromTabId As Integer, _

   ByVal toTabs As ArrayList, _

   ByVal includeSettings As Boolean)

The first parameter, moduleId, is the id of the module you want to copy to other pages. The second parameter, fromTabId, is the id of the page that the module currently lives on. The third parameter, toTabs, is an ArrayList of TabInfo objects that represent the different pages that you want to copy the module to. You can build your own list, or you can use the Globals.GetPortalTabs() method (from the DotNetNuke.Common namespace) to get a list of all the pages in your portal.

ArrayList allModulesAL =

   Globals.GetPortalTabs();

Finally, the last parameter to CopyModule() is a Boolean that specifies whether or not the settings associated with the module/page combination should be copied to the new module/page combination.

In this example, the current module gets copied to every page in the current portal:

// GET CURRENT MODULE'S DATA

ModuleController modController = new ModuleController();

ModuleInfo mod = modController.GetModule(ModuleId, TabId);

 

// MANUALLY ADD MODULE TO ALL TABS

ArrayList allTabsList =

   Globals.GetPortalTabs(

   PortalSettings.DesktopTabs, false, true);

modController.CopyModule(ModuleId,

   TabId, allTabsList, true);

Removing Modules from a Page

There are several different ways to delete modules using the ModuleController class. The method you use will depend on the behavior that you need.

The first method you might find in the ModuleController class is the DeleteModule() method. This method is not usually useful to the module developer. When you call this alone, it will delete the module info from the Modules table in the database. This is problematic because it could leave orphaned data that still is associated with the deleted module. Before you decide to use this method you should do some research and find out what steps you need to take to prevent this scenario.

A more useful method is the DeleteTabModule() method:

Public Sub DeleteTabModule(ByVal TabId As Integer,_

   ByVal ModuleId As Integer)

This method removes one module from one page. The TabId parameter is the id of the page you wish to remove the module from. The ModuleId parameter is the id of the module that you wish to remove from the page that you specified in the first parameter. The following example removes the current module from the current page:

ModuleController modController = new ModuleController();

modController.DeleteTabModule(TabId, ModuleId);

The final method for removing module instances is what I believe to be the most useful. The DeleteAllModules() method of the ModuleController class removes module instances from any number of pages. This method is very similar to the CopyModule() method in that it takes an ArrayList of TabInfo objects. The TabInfo objects in this ArrayList represent the pages that you need to remove the module from.

Public Sub DeleteAllModules(ByVal moduleId As Integer, _

   ByVal tabId As Integer, ByVal fromTabs As ArrayList, _

   ByVal includeCurrent As Boolean, _

   ByVal deleteBaseModule As Boolean)

The moduleId parameter is the id of the module you need to remove from the pages. The tabId parameter is the id of a page that the module exists on. Typically you would pass the id of the current page being rendered, if one exists. The fromTabs parameter is the ArrayList mentioned above. It contains TabInfo objects that represent all the pages that you wish to remove the module from. The third parameter, includeCurrent, is a Boolean value that specifies whether or not to remove the module from the page that you specified via the tabId parameter. If you set this parameter to false the module will be removed from all the pages listed in the fromTabs ArrayList, except for pages that have an id matching the second parameter of this method, tabId. Finally, the deleteBaseModule parameter is a Boolean value that specifies whether or not to delete the actual module record from the Modules table. Passing true here will call the DeleteModule() method that we talked about above.

Here is an example of how you can remove the current module from every page in the current portal, except the current page:

// GET CURRENT MODULE'S DATA

ModuleController modController = new ModuleController();

modController.DeleteTabModule(TabId, ModuleId);

 

// MANUALLY REMOVE MODULE FROM TABS

ArrayList allTabsList =

   Globals.GetPortalTabs(

        PortalSettings.DesktopTabs, false, true);

modController.DeleteAllModules(

   ModuleId, TabId, allTabsList, false, false);

Finally, I will leave you with a useful block of code. The ToggleAllTabs() method accepts a ModuleId, a PortalId, and a TabId. It first retrieves a ModuleInfo object for the current page+module combination. It then toggles the AllTabs property of the module. Depending on the state of AllTabs, the module is either added to all the tabs in the portal, or it is removed from all the tabs in the portal except for the current tab.

public void ToggleAllTabs(int ModuleId,

   int PortalId, int TabId)

{

   // GET CURRENT MODULE'S DATA

   ModuleController modController =

        new ModuleController();

   ModuleInfo mod =

        modController.GetModule(ModuleId, TabId);

 

   // TOGGLE AllTabs VALUE AND UPDATE

   mod.AllTabs = !mod.AllTabs;

   modController.UpdateModule(mod);

 

   if (mod.AllTabs)

   {

        // MANUALLY REMOVE MODULE FROM TABS

        ArrayList allTabsList =

            Globals.GetPortalTabs(

            PortalSettings.DesktopTabs, false, true);

        modController.DeleteAllModules(

            ModuleId, TabId, allTabsList, false, false);

   }

   else

   {

        // MANUALLY ADD MODULE TO ALL TABS

        ArrayList allTabsList =

            Globals.GetPortalTabs(

            PortalSettings.DesktopTabs, false, true);

        modController.CopyModule(

            ModuleId, TabId, allTabsList, true);

   }           

}

To Summarize

  1. Use the DotNetNuke.Entities.Modules namespace to access classes that will assist you in adding, removing, and all-around managing of modules.
  2. The ModuleInfo class houses all the information about a particular  module on a particular page.
  3. The ModuleController contains all the functionality you need to add, copy, update, and delete modules.
  4. You can create new instances of a module by calling the AddModule() method on an instance of the ModuleController class.
  5. You can copy an existing module instance to other pages by calling the CopyModule() method on an instance of the ModuleController class.
  6. You can remove one module from one page by calling the DeleteTabModule() method on an instance of the ModuleController class.
  7. You can remove one module from any number of pages by calling the DeleteAllModules() method on an instance of the ModuleController class.

This is part IV of the Making Your DotNetNuke Module Do More For You series where I attempt to bridge the gap between knowing DotNetNuke module basics and knowing how to add the precise functionality that you ideally would like your modules to have. In this series we are primarily focusing on using the built-in functionality of the DotNetNuke Framework core. In part III I showed you how to use personalization to store unique information for each user: Let’s Talk DotNetNuke User Personalization.

Today we will continue building your page modification skills. We will be exploring the DotNetNuke.Entities.Tabs namespace and using classes from that namespace to programmatically add pages to your site from within a module.

Let’s get to work!

The DotNetNuke.Entities.Tabs Namespace

In the early days of DotNetNuke, the Nuke vernacular used the term “Tab” to refer to a DotNetNuke page. This is why in many places in the framework you will see the term Tab instead of Page. Such is the case with the classes we will work with today.

The DotNetNuke.Entities.Tabs namespace contains a class that represents a page (the TabInfo class), and a class that does a lot of business logic for a page (the TabController class).

DotNetNuke.Entities.Tabs.TabInfo

Take a minute and navigate to the Page Management area of a page in your DotNetNuke site. You can reach this area by clicking on the “Settings” icon in the control panel.

image

The settings on the Page Management page have an almost one-to-one relationship with the TabInfo class. In fact, when you click “Update” on the bottom of the page, the code inside DotNetNuke’s ManageTabs control parses out the information from the Page Management form and uses the data to set all the properties of a new or existing instance of the TabInfo class. Here is a code snippet from DotNetNuke's ManageTabs control. As you can see, the page properties are truly being shoved right into a TabInfo object:

  215 Dim objTab As New TabInfo

  216 

  217 objTab.TabID = TabId

  218 objTab.PortalID = PortalId

  219 objTab.TabName = txtTabName.Text

  220 objTab.Title = txtTitle.Text

  221 objTab.Description = txtDescription.Text

  222 objTab.KeyWords = txtKeyWords.Text

  223 objTab.IsVisible = chkMenu.Checked

  224 objTab.DisableLink = chkDisableLink.Checked

  225 objTab.ParentId = Int32.Parse(cboTab.SelectedItem.Value)

  226 objTab.IconFile = strIcon

  227 objTab.IsDeleted = False

  228 objTab.Url = ctlURL.Url

  229 objTab.TabPermissions = dgPermissions.Permissions

  230 objTab.SkinSrc = ctlSkin.SkinSrc

  231 objTab.ContainerSrc = ctlContainer.SkinSrc

The same technique can be used by your module. Once you get an instance of the TabInfo class, you can programmatically set all the same page properties that the Page Management page sets.

Here’s a look at all the public properties that the TabInfo class makes available to you:

image

Most of the properties of TabInfo are self explanatory, but there are a few settings that can leave you scratching your head.

The biggest difficulty I experienced with the TabInfo class was setting the TabPermissions property. This property is of type DotNetNuke.Security.Permissions.TabPermissionCollection. As you probably already guessed, this property exposes the security permissions for the page you are creating or modifying. You use this property to define what users and roles can view and edit the page. How I learned the best way to configure these permissions was to sit through a 2 hour lecture on DotNetNuke page permissions. Luckily you won’t be doing that today, because I found a fast and mindless way to get you going quickly.

You will be using the TabPermissionGrid control that ships with DotNetNuke. Just follow these steps:

1. Use a page directive to register the control so that your page knows what a TabPermissionGrid is.

image

2. Create an instance of a TabPermissionGrid on your page:

image

3. From your code-behind, set the TabID property of the TabPermissionGrid to -1.

   48 if (!Page.IsPostBack)

   49 {

   50    PermGrid.TabID = -1;

4. On post-back, grab the Permissions property of the TabPermissionGrid instance. This property happens to be of type TabPermissionCollection, the same type as your TabInfo class’s TabPermissions property).

   82 newTab.ParentId = int.Parse(ParentsDropDownList.SelectedValue);

The TabPermissionGrid renders a control that allows you to configure permissions visually in a roles/users/permissions matrix.

image

Now tell me that is not quick and mindless. I love it.

Learning the nuts and bolts of the DotNetNuke.Security.Permissions namespace isn’t on the menu for today’s post. But subscribe to my feed; I will be covering this topic in an upcoming article.

More TabInfo properties – uncovered!

There are a few more properties that might give you headaches. Let’s review them:

1. TabInfo.IsDeleted – Unless your new page has a deathwish, you should probably set this property to false.

2. TabInfo.IsSuperTab – As great as you might believe your page to be, it probably is not super. Super tabs are pages under the Host Menu Item, like Host Settings, Modules Definitions, and stuff like that. Set this property to false.

3. TabInfo.IsVisible – This is a flag that gets wired up to the “include in menu” checkbox that is on the Page Settings page. Set this to true if you want your page to show up in the menu. Set it to false if you wish to keep your page from being listed in the menu.

4. TabInfo.DisableLink – This option lets you disable the page, which essentially makes your page not available to users of the site. This is the property that gets wired up to the “Disabled” check box in the Page Settings area.

Adding Pages Using the TabController Class

Now that you have populated the TabInfo object that represents your new page, how do you add the page to your site? This is the job of the TabController class.

This class has methods to add, copy, delete, retrieve, and update pages of the site. Today we will only focus on the AddTab method.

  323 Public Function AddTab(ByVal objTab As TabInfo) As Integer

Tab.Controller.AddTab() simply takes an instance of a TabInfo class and does all the page magic for you. After AddTab() creates the page, it returns the tab id of the newly created page.

By default, all the pages created using this method receive instances of the modules configured to appear on all pages. If you wish to not have the “all pages” modules appear on the page you are creating you can use an overloaded version of the AddTab() method:

  327 Public Function AddTab(ByVal objTab As TabInfo, ByVal AddAllTabsModules As Boolean) As Integer

This version takes the TabInfo object just as the regular version does. The second parameter is a Boolean value used to specify if the “all pages” modules should be shown or not. Pass true to show those modules, or false to not show them on the new page.

Don't Forget to Clear the Module Cache!

One final thing you must do in order for you new page to show up right away is to clear the Module Cache. So don't forget to do it!

   90 // clear cache

   91 DataCache.ClearModuleCache(newTab.TabID);

All Together Now!

And that’s all there is to programmatically creating DotNetNuke modules! Let's put it all together now:

    1 TabController controller = new TabController();

    2 TabInfo parentTab = controller.GetTab(

    3    int.Parse(ParentsDropDownList.SelectedValue),

    4    PortalId,true);

    5 TabInfo newTab = new TabInfo();

    6 

    7 newTab.PortalID = PortalId;

    8 newTab.TabName = TextBox1.Text.Trim();

    9 newTab.Title = TextBox2.Text.Trim();

   10 newTab.Description = TextBox3.Text.Trim();

   11 newTab.KeyWords = TextBox4.Text.Trim();

   12 newTab.IsDeleted = false;

   13 newTab.IsSuperTab = false;

   14 newTab.IsVisible = true;

   15 newTab.DisableLink = false;

   16 newTab.IconFile = "";

   17 newTab.Url = "";

   18 newTab.ParentId = int.Parse(

   19    ParentsDropDownList.SelectedValue);

   20 newTab.TabPermissions = PermGrid.Permissions;

   21 

   22 controller.AddTab(newTab);

   23 

   24 // clear cache

   25 DataCache.ClearModuleCache(newTab.TabID);

Download the Example Code

WorkingWithTabsCS.zip

To Summarize

1. The DotNetNuke.Entities.Tabs namespace is the key to programmatically creating pages. This namespace is where you can find the TabInfo and the TabController classes.

2. The TabInfo class embodies all the properties that you need to set on your new page. Begin by creating a new instance of TabInfo, and proceed to set all its properties.

3. If appropriate, you can leverage the TabPermissionGrid in your page in order to help you populate the Permissions property of your new TabInfo object.

4. To add a page, pass your new instance of TabInfo to the AddTab() method of an instance of the TabController class.

5. Go feed the dog.

Thanks for reading! I hope some readers find this information useful. If you happen to find some inaccuracies in my tutorial or have something to add, then please leave some feedback.

If you’re beginning to get the hang of programming DotNetNuke modules, then stick around. I have some disturbingly mind-blowing information coming up that beginning modules developers won’t want to miss.

Who Is Rafe

rafe

I Am Rafe Kemmis

I am an audacious entrepreneur with a double bachelor of science in Computer Science and Mathematics. I specialize in Microsoft ASP.Net web application development as well as accredited information systems auditing.

Questions?

Always a thoughtful response. You may post your question on an article, or contact me directly.

Hire Me.

I provide custom solutions to complex problems. I can help your business no matter how large or small.

Contact me now.

Subscribe