Last post Mar 01, 2006 11:36 AM by imagemaker
Feb 27, 2006 05:42 PM|gmessoroch|LINK
I'm working on development of a group of custom DNN modules for my company. There are a couple of issues we're debating, and would like to solicit opinions from anyone who is willing to share.
1. Common inter-module Data Provider, in addition to the standard data provider - Some of the database functionality is shared among modules, and we're thinking of putting that common functionality in a common data provider.
For example, if you consider a timesheet and expense tracking modules, both of these modules may have to call a function to get a list of clients (e.q. time billed to a given client, and expense billed to a given client).
Does it make sense to group all such common functionality in the same place, so it's maintained in one spot? Is it feasible to implement this approach within the DNN framework?
2. Consider and ETL process that moves data from one database to another. This would be a situation where a single module would need to be able to connect to multiple databases. Has anyone encountered this scenario, and, if so, how can it be handled within
Feb 27, 2006 08:47 PM|imagemaker|LINK
I've been dealing with both issues - particularly the first on a DNN 3 targeted set of modules that all reference the same set of database tables containing information for a statewide organization of community access television channels - contact and membership
information, facility capabilities, etc. Here are a few thoughts:
1. In cases such as this, data access is no longer tied to the TabModuleId or even to the ModuleId as is the case with most other modules. Such data must be shared by all instances of the same module definition or even among several related modules.
2. I first started creating various separate modules referencing the same data but found that I was often repeating much of the same code even though I made extensive uses of classes for handling both data objects and configuration settings. I then moved
to the pattern of writing a single base or container module that would then (based on either TabModuleSettings or user selection) dynamically load one or more child user controls to display/edit etc. various views of the data - basically a plug-in component
implementing a well defined interface. This has worked extremely well in that it reduces the need for intermodule communication and allows various views to be shown in the same panel of the same "page" without the annoying default DNN behavior of switching
to an admin page for any module control other than the default view control. Also, by having much of the functionality based in one module, I was able to define settings (such as data access specifications, upload image re-sizes and role permissions) based
on the ModuleDefId that would be global to all instances of this module or even across portals.
3. I've just begun to deal with the issues of a module having to connect to multiple databases - DNN's main database and a legacy MS access database (that now gets FTP's up to the web host daily) in a series of modules I've just started in DNN 4. This has
forced me write an OleDbDataProvider and decide how best to specify its connection string, etc. I'm currently trying to decide if it's best store this connection information in global ModuleDefSettings, in a separate module config file, or in web.config. The
organization will also be shifting within a year from MS Access to SQL Express Server 2005 which won't lend itself to uploading a database file, so I'm thinking of going with a webservice that would handle the daily receipt of the new data from a smart client
application and its syncronization into tables in either the main DNN database or a separate SQL Server database. Interfacing with both the main DNN and a second database is no real problem that writing two module controllers/DataProviders/SqlDataProviders
AND very careful namespacing can't handle.
Feb 28, 2006 04:10 PM|gmessoroch|LINK
Thank you for your insight.
Could you please elaborate (or point to a good resource) on coding a:
"single base or container module that would then (based on either TabModuleSettings or user selection) dynamically load one or more child user controls to display/edit etc. various views of the data "
Mar 01, 2006 11:36 AM|imagemaker|LINK
Here's the basic pattern:
1. In your module settings control include a way for the initial child view to be selected. When the settings are updated, I store a "view key" in the TabModuleSettings table:
If rblInitialView.SelectedItem Is Nothing Then
objModuleController.UpdateTabModuleSetting(TabModuleId, "view", "STD")
objModuleController.UpdateTabModuleSetting(TabModuleId, "view", rblInitialView.SelectedItem.Value)
2. Create a base class (inheriting from PortalModuleBase or a class that inherits from PortalModuleBase) for your child view controls that at the minimum includes the following:
Public Class ModuleViewBase
Private _DataSource As Object
Private _ParentModule As PortalModuleBase
Public Property DataSource() As Object
Set(ByVal Value As Object)
_DataSource = Value
Public Property ParentModule As PortalModuleBase
Set(ByVal Value As PortalModuleBase)
_ParentModule = Value
Private Overrides ReadOnly Property ModuleConfiguration() As DotNetNuke.Entities.Modules.ModuleInfo
Public Event RefreshRequested As EventHandler
Public Overridable Sub BindView()
Public Overridable Sub OnRefreshView()
RaiseEvent RefreshRequested(Me, New System.EventArgs)
3. Create your view controls (.ascx and .ascx.vb) inheriting from your view base class defined above. In each view control, provide overrides of the BindView sub as necessary to bind data to the view's controls (such as a datagird or dataview) when the parent
module calls the view's BindView() method. If the view control needs to have its data refreshed by the parent module, it should call it's OnRefreshView method.
4. Create your parent module control such that it contains in the declaritive HMML markup a PlaceHolder server control positioned where you want the child view control to occur. In the following code, the place holder is referenced as "phView". Also declare
the protected member:
Protected WithEvents _ViewControl As ModuleViewBase
5. In the Load handler of the module control's codebehind/codebeside load the appropriate child view control as follows:
Dim View As String
If Settings("view") Is Nothing OrElse Ctype(Settings("view"), String).Length=0 Then
View = "STD"
View = CType(Settings("view"), String)
Select Case View
_ViewControl = CType(LoadControl(ModulePath & "Centers_Standard.ascx"), Centers_Standard)
_ViewControl = CType(LoadControl(ModulePath & "Centers_Report.ascx"), Centers_Report)
_ViewControl = CType(LoadControl(ModulePath & "Centers_Websites.ascx"), Centers_Websites)
_ViewControl = CType(LoadControl(ModulePath & "Centers_EMails.ascx"), Centers_EMails)
ViewControl = CType(LoadControl(ModulePath & "Centers_Membership.ascx"), Centers_Membership)
If Not _ViewControl Is Nothing Then
_ViewControl.ParentModule = Me
AddHandler _ViewControl.RefreshRequested, AddressOf ViewControl_RefreshRequested
If Not IsPostBack Then BindView()
In the BindView method of you parent module you would retrieve the data to be displayed in the child view control, set it's DataSource property and call its BindView method:
Public Sub BindView()
_ViewControl.DataSource = GetData(DataFilter(), CurrentPage, PageSize)
If CType(_ViewControl.DataSource, ArrayList).Count = 0 Then
phView.Visible = False
ShowError("No access centers meeting the search/filter criteria were found.")
phView.Visible = True
If the child view control needs to have its data refreshed, it can raise the event RefreshRequested which is handled in the parent module with the following event handler:
Private Sub ViewControl_RefreshRequested(ByVal sender As System.Object, ByVal e As System.EventArgs)
CurrentPage = 1
I hope this gives you some help in one of many ways this can be done. The design of your ModuleView base class could include many more properties/events for intreaction with the parent. As I've started using the same pattern in a number of modules, I'm
in the process of writing a more extensible way to define module views which will include storing their definition in a ModuleView table that is similar to the core ModuleDefinition table. I also see this as a way to visually subdivide a module into zones
or panels - something that I feel needs to be in the core eventually.