Summary


Module Interfaces

Modules represent a discrete set of functionality that can extend the portal framework. In past versions of DotNetNuke, module interactions with the portal were primarily limited to making method calls into the core portal APIs. Though this one-way interaction provides some capability to use portal services and methods within the module, it limits the capability of the portal to provide more advanced services.

To provide two-way interactions with modules, the portal needs to have a mechanism to make method calls into the module. There are several distinct mechanisms for allowing a program to call methods on an arbitrary set of code, where the module code is unknown at the time the portal is being developed. Three of these "calling" mechanisms are used within DotNetNuke:

  • Inheritance

  • Delegates

  • Interfaces

As discussed previously, every module inherits from the PortalModuleBase class (located in the components/module directory). This base class provides a common set of methods and properties that can be used by the module as well as the portal to control the behavior of each module instance. Because the module must inherit from this class, the portal has a set of known methods that it can use to control the module. The portal could extend the base class to add methods to handle new services. One downside to this approach is that there is not an easy mechanism for determining whether a subclass implements custom logic for a specific method or property. Because of this restriction, inheritance is generally limited to providing services that are needed or required for every subclass.

A second method for interacting with the modules involves the use of delegates. A delegate is essentially a pointer to a method that has a specific set of parameters and return type. Delegates are useful when a service can be implemented with a single method call and are the underlying mechanism behind VB.NET's event handling. DotNetNuke uses delegates to implement callback methods for the Module Action menu action event. Although delegates are very useful in some situations, they are more difficult to implement and understand than alternative methods.

The third calling mechanism used by DotNetNuke is the use of interfaces. An interface defines a set of methods, events, and properties without providing any implementation details for these elements. Any class that implements an interface is responsible for providing the specific logic for each method, event, and property defined in the interface. Interfaces are especially useful for defining optional services that a module may implement. The portal can detect if a class implements a specific interface and can then call any of the methods, events, or properties defined in the interface.

Starting in version 3.0, DotNetNuke significantly extended its use of module interfaces. Six main interfaces are intended for use by modules:

  • IActionable

  • IPortable

  • IUpgradeable

  • IModuleCommunicator

  • IModuleListener

  • ISearchable

IActionable

Every module has a menu that contains several possible action items for activities like editing module settings, module movement, and viewing help. These menu items are called Module Actions. The module menu can be extended with your own custom actions. When your module inherits from the PortalModuleBase class, it receives a default set of actions, which are defined by the portal to handle common editing functions. Your module can extend these actions by implementing the IActionable interface.

Interface

As shown in Listing 8-18, the IActionable interface consists of a single method that returns a collection of Module Actions. The ModuleActions property is used when DotNetNuke renders the module.

Listing 8-18: IActionable Interface Definition

image from book
 Namespace DotNetNuke.Entities.Modules   Public Interface IActionable     ReadOnly Property ModuleActions() As Actions.ModuleActionCollection   End Interface End Namespace 
image from book

Listing 8-19 shows an example usage as implemented in the Announcements module. The first two lines tell the compiler that this method implements the ModuleAction method of the IActionable interface. It is a read-only method, so you only need to provide a Get function. The first step is to create a new collection to hold the custom actions. Then you use the collection's Add method to create a new action item in the collection. Finally, you return the new collection.

Listing 8-19: IActionable.ModuleActions Example

image from book
 Public ReadOnly Property ModuleActions() As ModuleActionCollection _   Implements IActionable.ModuleActions   Get     Dim Actions As New ModuleActionCollection     Actions.Add(GetNextActionID, _                 Localization.GetString(ModuleActionType.AddContent, _                                        LocalResourceFile), _                 ModuleActionType.AddContent, _                 "", _                 "", _                 EditUrl(), _                 False, _                 Security.SecurityAccessLevel.Edit, _                 True, _                 False)     Return Actions   End Get End Property 
image from book

This is a simple example that demonstrates the basic steps to follow for your own custom module menus. DotNetNuke provides extensive control over each Module Action.

ModuleAction API

To take full advantage of the power provided by Module Actions and the IActionable interface, you need to examine the classes, properties, and methods that make up the Module Action API.

Table 8-7 lists the classes that comprise the Module Action API.

Table 8-7: Module Action Classes

Class

Description

ModuleAction

Defines a specific function for a given module. Each module can define one or more actions that the portal will present to the user. Each module container can define the skin object used to render the Module Actions.

ModuleActionType

Defines a set of constants used for distinguishing common action types.

ModuleActionCollection

A collection of Module Actions.

ModuleActionEventListener

Holds callback information when a module registers for Action events.

ActionEventArgs

Passes data during the click event that is fired when a Module Action is selected by the user.

ActionEventHandler

A delegate that defines the method signature required for responding to the Action event.

ActionBase

Creates ModuleAction skin objects. The core framework includes three different implementations: SolPartActions.ascx, DropDown-Actions.ascx, and LinkActions.ascx.

The ModuleAction class is the heart of the API. Tables 8-8 and 8-9 show the properties and methods available in the ModuleAction class. Each item in the Module Action menu is represented by a single ModuleAction instance.

Table 8-8: ModuleAction Properties

Property

Type

Description

Actions

ModuleActionCollection

Contains the collection of Module Action items that can be used to form hierarchical menu structures. Every skin object that inherits from Action-Base may choose how to render the menu based on the capability to support hierarchical items. For example, the default SolpartActions skin object supports submenus, while the DropDownActions skin object only supports a flat menu structure.

Id

Integer

Every Module Action for a given module instance must contain a unique Id. The PortalModuleBase class defines the GetNextActionId method, which can be used to generate unique Module Action IDs.

CommandName

String

Distinguishes which Module Action triggered an action event. DotNetNuke includes 19 standard ModuleActionTypes that provide access to standard functionality. Custom Module Actions can use their own string to identify commands recognized by the module.

CommandArgument

String

Provides additional information during action event processing. For example, the DotNetNuke core uses CommandArgument to pass the Module ID for common commands like DeleteModule .Action.

Title

String

Sets the text that is displayed in the Module Action menu.

Icon

String

Name of the Icon file to use for the Module Action item.

Url

String

When set, this property allows a menu item to redirect the user to another web page.

ClientScript

String

JavaScript to run during the menuClick event in the browser. If the ClientScript property is present, it is called prior to the postback occurring. If the ClientScript returns false, the postback is canceled.

UseActionEvent

Boolean

Causes the portal to raise an Action Event on the server and notify any registered event listeners. If UseActionEvent is false, the portal handles the event, but does not raise the event back to any event listeners. The following CommandNames prevent the Action Event from firing: Module-Help, OnlineHelp, ModuleSettings, Delete-Module, PrintModule, ClearCache, MovePane, MoveTop, MoveUp, MoveDown, and MoveBottom.

Secure

SecurityAccessLevel

Determines the required security level of the user. If the current user does not have the necessary permissions, the Module Action is not displayed.

Visible

Boolean

If set to false, the Module Action will not be displayed. This property enables you to control the visibility of a Module Action based on custom business logic.

NewWindow

Boolean

Forces an action to open the associated URL in a new window. This property is not used if UseActionEvent is true or if the following CommandNames are used: ModuleHelp, Online Help, ModuleSettings, or PrintModule.

Table 8-9: ModuleAction Method

Method

Return Type

Description

HasChildren

Boolean

Returns true if the ModuleAction .Actions property has any items (Actions.Count > 0).

DotNetNuke includes several standard Module Actions that are provided by the PortalModuleBase class or that are used by several of the core modules. These ModuleActionTypes are shown in Listing 8-20. ModuleActionTypes can also be used to access localized strings for the ModuleAction.Title property. This helps promote a consistent user interface for both core and third-party modules.

Listing 8-20: ModuleActionTypes

image from book
 Public Class ModuleActionType   Public Const AddContent As String = "AddContent.Action"   Public Const EditContent As String = "EditContent.Action"   Public Const ContentOptions As String = "ContentOptions.Action"   Public Const SyndicateModule As String = "SyndicateModule.Action"   Public Const ImportModule As String = "ImportModule.Action"   Public Const ExportModule As String = "ExportModule.Action"   Public Const OnlineHelp As String = "OnlineHelp.Action"   Public Const ModuleHelp As String = "ModuleHelp.Action"   Public Const PrintModule As String = "PrintModule.Action"   Public Const ModuleSettings As String = "ModuleSettings.Action"   Public Const DeleteModule As String = "DeleteModule.Action"   Public Const ClearCache As String = "ClearCache.Action"   Public Const MoveTop As String = "MoveTop.Action"   Public Const MoveUp As String = "MoveUp.Action"   Public Const MoveDown As String = "MoveDown.Action"   Public Const MoveBottom As String = "MoveBottom.Action"   Public Const MovePane As String = "MovePane.Action"   Public Const MoveRoot As String = "MoveRoot.Action" End Class 
image from book

DotNetNuke provides standard behavior for the following ModuleActionTypes: ModuleHelp, OnlineHelp, ModuleSettings, DeleteModule, PrintModule, ClearCache, MovePane, MoveTop, MoveUp, MoveDown, and MoveBottom. All ModuleActionTypes in this subset will ignore the UseActionEvent and NewWindow properties. The ModuleActionTypes can be further subdivided into three groups:

  • Basic redirection: The ModuleActionTypes that perform simple redirection and cause the user to navigate to the URL identified in the URL property: ModuleHelp, OnlineHelp, ModuleSettings, and PrintModule.

  • Module movement: The ModuleActionTypes that change the order or location of modules on the current page: MovePane, MoveTop, MoveUp, MoveDown, and MoveBottom.

  • Custom logic: The ModuleActionTypes with custom business logic that use core portal APIs to perform standard module-related actions: DeleteModule and ClearCache.

DotNetNuke uses a custom collection class for working with Module Actions. The ModuleActionCollection inherits from .Net System.Collections.CollectionBase class and provides a strongly typed collection class. That minimizes the possibility of typecasting errors that can occur when using generic collection classes such as ArrayList.

Most module developers only need to worry about creating the ModuleActionCollection to implement the IActionable interface. Listing 8-21 shows the two primary methods for adding ModuleActions to the collection. These methods wrap the ModuleAction constructor method calls.

Listing 8-21: Key ModuleActionCollection Methods

image from book
 Public Function Add(ByVal ID As Integer, _    ByVal Title As String, _    ByVal CmdName As String, _    Optional ByVal CmdArg As String = "", _    Optional ByVal Icon As String = "", _    Optional ByVal Url As String = "", _    Optional ByVal UseActionEvent As Boolean = False, _    Optional ByVal Secure As SecurityAccessLevel = SecurityAccessLevel.Anonymous, _    Optional ByVal Visible As Boolean = True, _    Optional ByVal NewWindow As Boolean = False) _    As ModuleAction Public Function Add(ByVal ID As Integer, _     ByVal Title As String, _     ByVal CmdName As String, _     ByVal CmdArg As String, _     ByVal Icon As String, _     ByVal Url As String, _     ByVal ClientScript As String, _     ByVal UseActionEvent As Boolean, _     ByVal Secure As SecurityAccessLevel, _     ByVal Visible As Boolean, _     ByVal NewWindow As Boolean) _     As ModuleAction 
image from book

Note 

The first method in Listing 8-21 uses optional parameters that are not supported by C#. This method is likely to be deprecated in future versions to simplify support for C# modules and its use is not recommended.

The ModuleAction framework makes it easy to handle simple URL redirection from a Module Action. Just like the Delete and ClearCache actions provided by the DotNetNuke framework, your module may require the use of custom logic to determine the appropriate action to take when the menu item is clicked. To implement custom logic, the module developer must create a response to a menu click event.

In the DotNetNuke architecture, the ModuleAction menu is a child of the module container. The module is also a child of the container. This architecture allows the framework to easily change out the menu implementation; however, it complicates communication between the menu and module. The menu never has a direct reference to the module and the module does not have a direct reference to the menu. This is a classic example of the Mediator design pattern. This pattern is designed to allow two classes without direct references to communicate. Figure 8-3 shows the steps involved to implement this pattern.

image from book
Figure 8-3

The following sections examine those steps and explore ways you can extend the framework.

Step 1: Register the Event Handler

The first step to implementing the Mediator pattern is to provide a mechanism for the module to register with the portal. The portal will use this information later when it needs to notify the module that a menu item was selected. Handling the click event is strictly optional. Your module may choose to use standard MenuActions, in which case you can skip this step. Because the module does not contain a direct reference to the page on which it is instantiated, you need to provide a registration mechanism.

The Skin class, which acts as the mediator, contains the RegisterModuleActionEvent method, which allows a module to notify the framework of the event handler for the action event (see Listing 8-22). Registration should occur in the module's Page_Load event to ensure that it happens before the event can be fired in the Skin class. The code in Listing 8-22 is from the HTML module and provides a working example of module-based event registration for the ModuleAction event. Although you could use another interface to define a known method to handle the event, the registration mechanism turns out to be a much more flexible design when implementing a single method.

Listing 8-22: Registering an Event Handler

image from book
 '---------------------------------------------------------------------------------- '-                        Menu Action Handler Registration                        - '---------------------------------------------------------------------------------- 'This finds a reference to the containing skin Dim ParentSkin As UI.Skins.Skin = UI.Skins.Skin.GetParentSkin(Me) 'We should always have a ParentSkin, but need to make sure If Not ParentSkin Is Nothing Then     'Register our EventHandler as a listener on the ParentSkin so that it may     'tell us when a menu has been clicked.     ParentSkin.RegisterModuleActionEvent(Me.ModuleId, AddressOf ModuleAction_Click) End If '---------------------------------------------------------------------------------- 
image from book

Listing 8-23 shows the ModuleAction_Click event handler code from the HTML module.

Listing 8-23: Handling the Event

image from book
 Public Sub ModuleAction_Click(ByVal sender As Object, _                               ByVal e As Entities.Modules.Actions.ActionEventArgs)   'We could get much fancier here by declaring each ModuleAction with a   'Command and then using a Select Case statement to handle the various   'commands.   If e.Action.Url.Length > 0 Then     Response.Redirect(e.Action.Url, True)   End If End Sub 
image from book

The DotNetNuke framework uses a delegate (see Listing 8-24) to define the method signature for the event handler. The RegisterModuleActionEvent requires the address of a method with the same signature as the ActionEventHandler delegate.

Listing 8-24: ActionEventHandler Delegate

image from book
 Public Delegate Sub ActionEventHandler(ByVal sender As Object, _                                        ByVal e As ActionEventArgs) 
image from book

Step 2: Display the Menu

Now that the skin (the Mediator class) can communicate with the module, you need a mechanism to allow the menu to communicate with the skin as well. This portion of the communication chain is much easier to code. Handling the actual click event and passing it to the skinning class is the responsibility of the ModuleAction rendering code.

Like much of DotNetNuke, the ModuleAction framework supports the use of custom extensions. In this case, skin objects handle rendering the Module Actions. Each ModuleAction skin object inherits from the DotNetNuke.UI.Containers.ActionBase class. The Skin class retrieves the Module Action collection from the module by calling the IActionable.ModuleActions property and passes the collection to the ModuleAction skin object for rendering. The ActionBase class includes the code necessary to merge the standard Module Actions with the collection provided by the Skin class.

Each skin object includes code in the pre-render event to convert the collection of Module Actions into an appropriate format for display using an associated server control. In the case of SolPartActions.ascx, the server control is a menu control that is capable of fully supporting all of the features of ModuleActions including submenus and icons. Other skin objects like the DropDownActions.ascx may only support a subset of the Module Action features (see Table 8-10).

Table 8-10: ModuleAction Skin Objects

Action Skin Object

Menu Separator

Icons

Submenus

Client-Side JavaScript

Actions or SolPartActions

Yes

Yes

Yes

Yes

DropDownActions

Yes

No

No

Yes

LinkActions

No

No

No

No

Step 3: Notify the Portal of a Menu Item Selection

Each skin object handles the click event of the associated server control. This event, shown in Listing 8-25, calls the ProcessAction method, which is inherited from the ActionBase class. ProcessAction is then responsible for handling the event as indicated by the ModuleAction properties. If you create your own ModuleAction skin object, follow this pattern.

Listing 8-25: Click Event Handler

image from book
 Private Sub ctlActions_MenuClick(ByVal ID As String) Handles ctlActions.MenuClick   Try     ProcessAction(ID)   Catch exc As Exception    'Module failed to load     ProcessModuleLoadException(Me, exc)   End Try End Sub 
image from book

Step 4: Notify the Module That a Custom ModuleAction Was Clicked

If the UseActionEvent is set to True, the ProcessAction method (see Listing 8-26) calls the OnAction method to handle actually raising the event (see Listing 8-27). This might seem like an extra method call when ProcessAction could just raise the event on its own. The purpose of OnAction, though, is to provide an opportunity for subclasses to override the default event handling behavior. Although this is not strictly necessary, it is a standard pattern in .NET and is a good example to follow when developing your own event handling code.

Listing 8-26: ProcessAction Method

image from book
 Public Sub ProcessAction(ByVal ActionID As String)   If IsNumeric(ActionID) Then     Dim action As ModuleAction = GetAction(Convert.ToInt32(ActionID))     Select Case action.CommandName       Case ModuleActionType.ModuleHelp         DoAction(action)       Case ModuleActionType.OnlineHelp         DoAction(action)       Case ModuleActionType.ModuleSettings         DoAction(action)       Case ModuleActionType.DeleteModule         Delete(action)       Case ModuleActionType.PrintModule         DoAction(action)       Case ModuleActionType.ClearCache         ClearCache(action)       Case ModuleActionType.MovePane         MoveToPane(action)       Case ModuleActionType.MoveTop, _            ModuleActionType.MoveUp, _            ModuleActionType.MoveDown, _            ModuleActionType.MoveBottom         MoveUpDown(action)       Case Else         ' custom action         If action.Url.Length > 0 And action.UseActionEvent = False Then           DoAction(action)         Else           ModuleConfiguration))         End If     End Select   End If End Sub 
image from book

Listing 8-27: OnAction Method

image from book
 Protected Overridable Sub OnAction(ByVal e As ActionEventArgs)   RaiseEvent Action(Me, e) End Sub 
image from book

Because the skin maintains a reference to the ModuleAction skin object, the Skin class can handle the Action event raised by the skin object. As shown in Listing 8-28, the Skin class iterates through ActionEventListeners to find the associated module event delegate. When a listener is found, the code invokes the event, which notifies the module that the event has occurred.

Listing 8-28: Skin Class Handles the ActionEvent

image from book
 Public Sub ModuleAction_Click(ByVal sender As Object, ByVal e As ActionEventArgs)   'Search through the listeners   Dim Listener As ModuleActionEventListener   For Each Listener In ActionEventListeners     'If the associated module has registered a listener     If e.ModuleConfiguration.ModuleID = Listener.ModuleID Then       'Invoke the listener to handle the ModuleAction_Click event       Listener.ActionEvent.Invoke(sender, e)     End If   Next End Sub 
image from book

You are now ready to take full advantage of the entire ModuleAction API to create custom menu items for your own modules, handle the associated Action event when the menu item is clicked, and create your own custom ModuleAction skin objects.

IPortable

DotNetNuke provides the capability to import and export modules within the portal. Like many features in DotNetNuke, it is implemented using a combination of core code and module-specific logic. The IPortable interface defines the methods required to implement this feature on a module-by-module basis (see Listing 8-29).

Listing 8-29: IPortable Interface Definition

image from book
 Public Interface IPortable   Function ExportModule(ByVal ModuleID As Integer) As String   Sub ImportModule(ByVal ModuleID As Integer, _                    ByVal Content As String, _                    ByVal Version As String, _                    ByVal UserID As Integer) End Interface 
image from book

This interface provides a much-needed feature to DotNetNuke and is a pretty straightforward interface to implement. To fully support importing and exporting content, implement the interface within your module's business controller class.

As modules are being loaded by the portal for rendering a specific page, they are checked to determine whether they implement the IPortable interface. To simplify checking whether a module implements the interface, a shortcut property has been added to the ModuleInfo class. The ModuleInfo class provides a consolidated view of properties related to a module. When a module is first installed in the portal, a quick check is made to determine if the module implements the IPortable interface, and if so, the IsPortable flag is set on the base ModuleDefinition record. This property allows the portal to perform the interface check without unnecessarily loading the business controller class. Adding the check at the point of installation removes a requirement by previous DotNetNuke versions for a module control to implement unused stub methods. If the control implements the IPortable interface, DotNetNuke automatically adds the Import Content and Export Content menu items to your Module Action menu (see Figure 8-4).

image from book
Figure 8-4

Each module should include a controller class that is identified in the BusinessControllerClass property of the portal's ModuleInfo class. This class is identified in the module manifest file discussed later in the book. The controller class is where you implement many of the interfaces available to modules.

Adding the IPortable interface to your module requires implementing logic for the ExportModule and ImportModule methods shown in Listing 8-30 and Listing 8-31, respectively.

Listing 8-30: ExportModule Stub

image from book
 Public Function ExportModule(ByVal ModuleID As Integer) As String _   Implements Entities.Modules.IPortable.ExportModule   Dim strXML As String = ""   Dim objHtmlText As HtmlTextInfo = GetHtmlText(ModuleID)   If Not objHtmlText Is Nothing Then     strXML += "<htmltext>"     strXML += "<desktophtml>{0}</desktophtml>"     strXML += "<desktopsummary>{1}</desktopsummary>"     strXML += "</htmltext>"     String.Format(strXML, _                   XMLEncode(objHtmlText.DeskTopHTML), _                   XMLEncode(objHtmlText.DesktopSummary))   End If   Return strXML End Function 
image from book

Listing 8-31: ImportModule Stub

image from book
 Public Sub ImportModule(ByVal ModuleID As Integer, _                         ByVal Content As String, _                         ByVal Version As String, _                         ByVal UserId As Integer) _   Implements Entities.Modules.IPortable.ImportModule   Dim xmlHtmlText As XmlNode = GetContent(Content, "htmltext")   Dim objText As HtmlTextInfo = New HtmlTextInfo   objText.ModuleId = ModuleID   objText.DeskTopHTML = xmlHtmlText.SelectSingleNode("desktophtml").InnerText   objText.DesktopSummary = xmlHtmlText.SelectSingleNode("desktopsummary").InnerText   objText.CreatedByUser = UserId   AddHtmlText(objText) End Sub 
image from book

The complexity of the data model for your module determines the difficulty of implementing these methods. Take a look at a simple case as implemented by the HTMLText module.

In Listing 8-30, the ExportModule method is used to serialize the content of the module to an XML string. DotNetNuke saves the serialized string along with the module's FriendlyName and Version. The XML file is saved into the portal directory.

The ImportModule method in Listing 8-31 reverses the process by deserializing the XML string created by the ExportModule method and replacing the content of the specified module. The portal passes the version information stored during the export process along with the serialized XML string.

The IPortable interface is straightforward to implement and provides much needed functionality to the DotNetNuke framework. It is at the heart of DotNetNuke's templating capability and therefore is definitely an interface that all modules should implement.

IUpgradeable

One of DotNetNuke's greatest features is the capability to easily upgrade from one version to the next. The heart of that is the creation of script files that can be run sequentially to modify the database schema and move any existing data to the new version's schema. In later versions, DotNetNuke added a mechanism for running custom logic during the upgrade process. Unfortunately, this mechanism was not provided for modules. Therefore, third-party modules were forced to create their own mechanism for handling custom upgrade logic.

This was fixed in DotNetNuke 3.0 and updated again in 4.1. The IUpgradeable interface (see Listing 8-32) provides a standard upgrade capability for modules, and uses the same logic as used in the core frame-work. The interface includes a single method, UpgradeModule, which enables the module to execute custom business logic depending on the current version of the module being installed.

Listing 8-32: IUpgradeable Interface

image from book
 Public Interface IUpgradeable   Function UpgradeModule(ByVal Version As String) As String End Interface 
image from book

UpgradeModule is called once for each script version included with the module. It is called only for script versions that are later than the version of the currently installed module.

Important 

Due to the behavior of ASP.NET when a new assembly is added to the \bin directory, the IUpgradeable interface could fail during installation. This behavior has been corrected in the 3.3 and 4.1 releases. If your module needs this interface for proper installation, have your users upgrade to the latest version of DotNetNuke.

Inter-Module Communication

DotNetNuke includes the capability for modules to communicate with each other through the Inter-Module Communication (IMC) framework. The IMC framework enables modules to pass objects rather than simple strings. Additionally, other properties enable a module to identify the Sender, the Target, and the Type of message. Take a look at the two main interfaces that provide this functionality to your module: ModuleCommunicator and IModuleListener.

IModuleCommunicator

The IModuleCommunicator interface defines a single event, ModuleCommunication, for your module to implement (see Listing 8-33).

Listing 8-33: IModuleCommunicator Interface

image from book
 Public Interface IModuleCommunicator   Event ModuleCommunication As ModuleCommunicationEventHandler End Interface 
image from book

To communicate with another module, first implement the IModuleCommunicator interface in your module. You should have an event declaration in your module as shown in Listing 8-34.

Listing 8-34: ModuleCommunication Event Implementation

image from book
 Public Event ModuleCommunication(ByVal sender As Object, _                                  ByVal e As ModuleCommunicationEventArgs) _                                  Implements IModuleCommunicator.ModuleCommunication 
image from book

IModuleListener

Whereas the IModuleCommunicator is used for sending messages, the IModuleListener interface (see Listing 8-35) is used for receiving messages.

Listing 8-35: IModuleListener Interface

image from book
 Public Interface IModuleListener   Sub OnModuleCommunication(ByVal s As Object, _                             ByVal e As ModuleCommunicationEventArgs) End Interface 
image from book

This interface defines a single method, OnModuleCommunication, which is called when an IModuleCommunicator on the same page raises the ModuleCommunication event. What you do in response to this event notification is totally up to you.

Note 

DotNetNuke does not filter event messages. Any module that implements the IModuleListener interface is notified when the event is raised. It is the responsibility of the module to determine whether it should take any action.

ISearchable

DotNetNuke provides a robust search API for indexing and searching content in your portal. The API is divided into three distinct parts:

  • Core search engine

  • Search data store

  • Search indexer

Like the ModuleAction framework, the search framework also implements a Mediator pattern. When combined with the Provider pattern, this framework provides lots of flexibility. In Figure 8-5, you can see the relationship between these patterns and the three parts of the search API.

image from book
Figure 8-5

The core search engine provides a simple API for calling the IndexProvider and then storing the results using a SearchDataStoreProvider. This API is intended for use by the core framework. Future versions of the API will be extended to allow modules greater control over the indexing process.

DotNetNuke includes a default implementation of the SearchDataStoreProvider, which is meant to provide basic storage functionality, but could be replaced with a more robust search engine. As for other providers, third-party developers are implementing providers for many of the current search engines on the market. You can find links to these providers and more at www.dotnetnuke.com and in the DotNetNuke Marketplace at http://marketplace.dotnetnuke.com.

The IndexingProvider provides an interface between the core search engine and each module. DotNetNuke includes a default provider that indexes module content. This provider can be replaced to provide document indexing, web indexing, or even indexing legacy application content stored in another database. If you decide to replace it, keep in mind that DotNetNuke only allows for the use of a single provider of a given type. This means that if you want to index content from multiple sources, you must implement this as a single provider. Future versions of the framework may be enhanced to overcome this limitation.

When using the ModuleIndexer, you can incorporate a module's content into the search engine data store by implementing the ISearchable interface shown in Listing 8-36.

Listing 8-36: ISearchable Interface

image from book
 Public Interface ISearchable   Function GetSearchItems(ByVal ModInfo As ModuleInfo) As SearchItemInfoCollection End Interface 
image from book

This interface is designed to allow almost any content to be indexed. By passing in a reference to the module and returning a collection of SearchItems, the modules are free to map their content to each SearchItem as they see fit. Listing 8-37 shows a sample implementation from the Announcements module included with DotNetNuke.

Listing 8-37: Implementing the Interface

image from book
 Public Function GetSearchItems(ByVal ModInfo As Entities.Modules.ModuleInfo) _   As Services.Search.SearchItemInfoCollection _   Implements Services.Search.ISearchable.GetSearchItems     Dim SearchItemCollection As New SearchItemInfoCollection     Dim Announcements As ArrayList = GetAnnouncements(ModInfo.ModuleID)     Dim objAnnouncement As Object     For Each objAnnouncement In Announcements       Dim SearchItem As SearchItemInfo       With CType(objAnnouncement, AnnouncementInfo)         Dim UserId As Integer         If IsNumeric(.CreatedByUser) Then           UserId = Integer.Parse(.CreatedByUser)         Else           UserId = 2         End If         SearchItem = New SearchItemInfo(ModInfo.ModuleTitle & "- "& .Title, _                        ApplicationURL(ModInfo.TabID), _                        .Description, _                        UserId, _                        .CreatedDate, _                        ModInfo.ModuleID, _                        "Anncmnt" & ModInfo.ModuleID.ToString & "-" & .ItemId, _                        .Description)         SearchItemCollection.Add(SearchItem)       End With     Next     Return SearchItemCollection End Function 
image from book

In this code, you make a call to your module's Info class, just as you would when you bind to a control within your ASCX file, but in this case the results are going to populate the SearchItemInfo, which will populate the DNN index with data from the module.

The key to implementing the interface is figuring out how to map your content to a collection of SearchItem Info objects. Table 8-11 lists the properties of the SearchItemInfo class.

Table 8-11: SearchItemInfo Properties

Property

Description

SearchItemId

An ID assigned by the search engine. It's used when deleting items from the data store.

Title

A string that is used when displaying search results.

Description

Summary of the content and is used when displaying search results.

Author

Content author.

PubDate

Date that allows the search engine to determine the age of the content.

ModuleId

ID of the module whose content is being indexed.

SearchKey

Unique key that can be used to identify each specific search item for this module.

Content

The specific content that will be searched. The default search data store does not search on any words that are not in the content property.

GUID

Another unique identifier that is used when syndicating content in the portal.

ImageFileId

Optional property used to identify image files that accompany a search item.

HitCount

Maintained by the search engine and used to identify the number of times that a search item is returned in a search.

Now that the index is populated with data, users of your portal can search your module's information from a unified interface within DNN.




Professional DotNetNuke 4.0 (c) Open Source Web Application Framework for ASP. NET 4.0
Professional DotNetNuke 4: Open Source Web Application Framework for ASP.NET 2.0 (Programmer to Programmer)
ISBN: 0471788163
EAN: 2147483647
Year: 2006
Pages: 182

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net