CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

David Hayden [MVP C#]

         .NET Tutorials, Patterns, and Practices

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.



Comments

help.net said:

# April 3, 2005 5:42 PM

help.net said:

# April 3, 2005 5:42 PM

Patrick Santry's (aka wwwCoder) Blog said:

# April 4, 2005 7:30 PM

David Hayden said:

As I&amp;nbsp;mentioned before,&amp;nbsp;Applying UML and Patterns by Craig Larman has an extensive description...
# April 8, 2005 11:25 AM

Jeff Perrin said:

# April 14, 2005 8:26 PM

David Hayden said:

Jeff Perrin has some excellent comments regarding my previous post describing the GRASP Controller Pattern,...
# April 15, 2005 10:22 AM

C# .Net Tales said:

I've been trying to set up my development machine with DotNetNuke 4.3.4 and get it debugging in Visual...

# September 14, 2006 3:13 AM

C# .Net Tales said:

I've been trying to set up my development machine with DotNetNuke 4.3.4 and get it debugging in Visual

# September 19, 2006 1:27 AM

Mirrored Blogs said:

Body: I&#39;ve been trying to set up my development machine with DotNetNuke 4.3.4 and get it debugging

# September 5, 2007 4:38 PM
Check out Devlicio.us!

This Blog

Syndication

News

CodeBetter.Com Home