DotNetNuke Architecture – Digging Into the DNN Source Code

I installed DotNetNuke (DNN) this weekend for the Sarasota, Florida .NET Developer Group website.  Since I had DNN on my test PC, I decided to view the source code to see how it was architected.  I was pleasantly pleased at how well organized the code was as well as how closely it resembled the Community Server source code.  DNN is written in VB.NET and Community Server is written in C#, but the architectures are very similar.


Since they are so similar, let’s walk through the source code like we did with Community Server in the following post:


Community Server Source Code – Abstract Classes, Reflection and Data Providers


One of the modules in DotNetNuke is the HTML Module.  The module is responsible for displaying blocks of HTML for the portal.  The usercontrol is called HtmlModule.ascx and if you look at the VB.NET in the code-behind you will see the following code snippet shown below. In Page_Load, the module instantiates a controller, of type HtmlTextController, to go out and get the HTML contents for this module based on its ModuleId. (For more information on controller, see Applying UML and Patterns: Controller GRASP Pattern – Model View Controller Design Pattern – First Object Beyond UI Layer.


 


HtmlModule.ascx.vb
Private Sub Page_Load



Dim objHTML As New HtmlTextController
Dim objDr As HtmlTextInfo = objHTML.GetHtmlText(ModuleId)



End Sub


 


The GetHtmlText function shown below has a few interesting things, many of which we talked about with the Community Server source code.  DataProvider.Instance() is a Factory Method that returns the concrete Data Provider class for the HTML Module.  GetHtmlText(…) is then called on this concrete class, which returns an object of IDataReaderCBO.FillObject is a helper function that will take an IDataReader and return a simple “hydrated” business object – in this case an object of type HtmlTextInfo.


 


HtmlTextController.vb
Public Function GetHtmlText(ByVal moduleId As Integer) As HtmlTextInfo

Return CType(CBO.FillObject(DataProvider.Instance().GetHtmlText(moduleId),
GetType(HtmlTextInfo)), HtmlTextInfo)

End Function


 


Let’s get back to the DataProver.Instance() factory method.  DataProvider is an abstract class from which the concrete data provider will inherit.  The Instance() method returns the concrete data provider:


 


DataProvider.vb
Public MustInherit Class DataProvider

#Region “Shared/Static Methods”

singleton reference to the instantiated object
Private Shared objProvider As DataProvider = Nothing

constructor
Shared Sub New()
CreateProvider()
End Sub

dynamically create provider
Private Shared Sub CreateProvider()
objProvider
= CType(Framework.Reflection.CreateObject(data,
DotNetNuke.Modules.Html, DotNetNuke.Modules.Html), DataProvider)
End Sub

return the provider
Public Shared Shadows Function Instance() As DataProvider
Return objProvider
End Function

#End Region

#Region “Abstract methods”


Public MustOverride Function
GetHtmlText(
ByVal moduleId As Integer) As IDataReader


#End Region

End Class


 


The concrete data provider is dynamically created on the fly using reflection.  The CreateProvider subroutine above calls Framework.Reflection.CreateObject (…) to create the object based on the parameter values sent to the helper class as well as the default “data” provider in the web.config file:


 


Reflection.vb
Public Class Reflection

Public Shared Function CreateObject(ByVal ObjectProviderType As String) As Object
Return CreateObject(ObjectProviderType, “”, “”)
End Function

Public Shared Function CreateObject(ByVal ObjectProviderType As String,
ByVal ObjectNamespace As String, ByVal ObjectAssemblyName As String) As Object

Dim TypeName As String =
Dim CacheKey As String =

Dim objProviderConfiguration As ProviderConfiguration =
ProviderConfiguration.GetProviderConfiguration(ObjectProviderType)

If ObjectNamespace <> “” And ObjectAssemblyName <> “” Then

TypeName = ObjectNamespace & . &
objProviderConfiguration.DefaultProvider
& , & ObjectAssemblyName & .”
& objProviderConfiguration.DefaultProvider

CacheKey = ObjectNamespace & . & ObjectProviderType & provider”
Else

TypeName = CType(objProviderConfiguration.Providers
(objProviderConfiguration.DefaultProvider), Provider).Type

CacheKey = ObjectProviderType & provider”
End If

Return CreateObject(TypeName, CacheKey)

End Function

Public Shared Function CreateObject(ByVal TypeName As String,
ByVal CacheKey As String) As Object

Dim objObject As Object

If CacheKey = “” Then
CacheKey
= TypeName
End If

Dim objType As Type = CType(DataCache.GetCache(CacheKey), Type)

If objType Is Nothing Then

Try
objType
= Type.GetType(TypeName, True)

DataCache.SetCache(CacheKey, objType)

Catch exc As Exception

LogException(exc)

End Try
End If

Return Activator.CreateInstance(objType)

End Function

End Class


 


Below is a snippet of the actual concrete class for Sql Server that is getting the html for the HTML Module. As I mentioned above, it only returns an IDataReader.  It is the CBO.FillObject(…) method that hydrates the IDataReader information into an HtmlTextInfo object.


 


SqlDataProvider.vb
Public Class SqlDataProvider
Inherits DataProvider


Public Overrides Function GetHtmlText(ByVal moduleId As Integer)
As IDataReader

Return CType(SqlHelper.ExecuteReader(ConnectionString,
DatabaseOwner
& ObjectQualifier & GetHtmlText,
moduleId), IDataReader)

End Function



End Class


 


As you can tell from the code and description above, DotNetNuke and Community Server share a lot of the same ideas.  You essentially have a usercontrol who’s code-behind calls a controller class.  The controller class calls an Instance() factory method on an abstract data provider class that returns the concrete data provider class.  Often this concrete class is instantiated using Reflection.  The data call is handed off to the concrete data provider class that returns, in this case, an IDataReader.  A business object is hydrated from the IDataReader class and the data reader and connection are closed.  And, last, the contents are dispayed in the usercontrol.


In the near future, I will build a similar architecture using the Create a Shopping Cart object so that we can add persistence to the class.

This entry was posted in C#, GRASP Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>