Learn More





DNN Community Blog

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.

Step by Step Webforms MVP and DotNetNuke – Part 1.

This morning at the QA team meeting we discussed the Testable DNN Module and its use of Webforms MVP to make it testable.  During the conversation we decided we needed some step by step information on how it all ties together in a “Michael Washington” style tutorial.  Charles Nurse has written up a great post on the theory behind the use of Webforms MVP here, so this tutorial will be more along the lines of what to do not why you do it.  Please make sure you read Charles’ post because I am assuming you have.

As a quick reminder here’s the list of parts Charles talks about.  There are four components for each MVP Module Control.

  1. An Interface which defines the View
  2. A Model class which will be passed between the Presenter and the View
  3. A Concrete View class (the User Control which renders the content to the Response stream) and
  4. A Presenter Class which manages everything

Interfaces for Everything

The main reason for moving your code out of the code behind file and into the presenter is so you can test it because now it is just a class and does not rely on there being a httpContext etc that a code behind file needs.  In addition to the classes Charles mentions above, to make sure your presenter class is fully testable you need to make sure that any time it calls another class that class has an interface so you can mock it out.  Take a look at the OnLoad method in EditTestDrivenDNNModulePresenter, you’ll see that it calls the controller class which means you need a controller class interface as well.  Along the same lines take a look at TestDrivenDNNModuleController and you’ll see it uses an interface when calling the SqlDataProvider.  Having an interface for each touch point makes it very easy to use a mocking framework such as Moq to create mocks for your tests.

The last class that I have in the solution that is not mentioned in Charles’ post is the UIEventArgs class.  This class is used to pass information from the View to the Presenter.  Take a look at the Save method in the EditTestDrivenDNNModulePresenter class. 

   1:  Public Sub Save(ByVal sender As Object, ByVal e As UIEventArgs(Of TestDrivenDNNModuleInfo))

Doing this allows the presenter to be given the data it requires without having to resort ot ViewState in the view.  This means you can actually turn off ViewState on your controls and save on the payload.

Build a WebformsMVP DNN Module

The following will lead you through how to build a WebformsMVP DNN Module starting from the StarterKit Compiled module.  The end result will be a module similar to the Testable DNN Module .  This article assumes you are using DNN 5.4.  You can get the latest code from CodePlex here  Part 1 gets you set up by modifying the existing files in the starter kit.

  1. Create a new Project and select the DotNetNuke Compiled Module option.
  2. Follow the setup instructions for the module.
  3. Change the .Net Framework version to .Net 3.5
  4. Add a reference to DotNetNuke.dll, DotNetNuke.Web.dll and WebFormsMVP.dll.
  5. In the Components folder add a folder for each of the following:
    1. Controller
    2. DataProvider
    3. Models
    4. Presenters
  6. Move the WebformsMVPController.vb file into the Controller folder
  7. Move the SqlDataProvider.vb and DataProvider.vb into the DataProvider folder.
  8. If you have a tool such as Resharper extract the interface for the WebformsMVPController into a separate file.  You should get an interace like this:
       1:  Namespace YourCompany.Modules.WebformsMVP
       2:      Public interface IWebformsMVPController
       3:          Function GetWebformsMVPs(ByVal ModuleId As Integer) As List(Of WebformsMVPInfo)
       4:          Function GetWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer) As WebformsMVPInfo
       5:          Sub AddWebformsMVP(ByVal objWebformsMVP As WebformsMVPInfo)
       6:          Sub UpdateWebformsMVP(ByVal objWebformsMVP As WebformsMVPInfo)
       7:          Sub DeleteWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer)
       8:      end interface
       9:  End NameSpace
  9. If you don’t have a refactoring tool create the interface above manually and then implement it on your like so:
    I have only shown the first method implemented.
       1:      Public Class WebformsMVPController
       2:          Implements Entities.Modules.ISearchable
       3:          Implements Entities.Modules.IPortable
       4:          Implements IWebformsMVPController
       6:  #Region "Public Methods"
       7:          Public Function GetWebformsMVPs(ByVal ModuleId As Integer) As List(Of WebformsMVPInfo) _
       8:              Implements IWebformsMVPController.GetWebformsMVPs
       9:              Return CBO.FillCollection(Of WebformsMVPInfo)(DataProvider.Instance().GetWebformsMVPs(ModuleId))
      10:          End Function
  10. Add two constructors to the controller.  The constructor with no arguments is used in production and the one with the IDataProvider passed in is used for testing. 
       1:          Private _DataProvider As IDataProvider
       3:          Public Sub New()
       4:              _DataProvider = DotNetNuke.ComponentModel.ComponentFactory.GetComponent(Of IDataProvider)()
       5:              If _DataProvider Is Nothing Then
       6:                  ' get the provider configuration based on the type
       7:                  Dim defaultprovider As String = DotNetNuke.Data.DataProvider.Instance.DefaultProviderName
       8:                  Dim dataProviderNamespace As String = "YourCompany.Modules.WebformsMVP"
       9:                  If defaultprovider = "SqlDataProvider" Then
      10:                      _DataProvider = New SqlDataProvider
      11:                  Else
      12:                      Dim providerType As String = dataProviderNamespace + "." + defaultprovider
      13:                      _DataProvider = CType(Framework.Reflection.CreateObject(providerType, providerType, True), IDataProvider)
      14:                  End If
      15:                  DotNetNuke.ComponentModel.ComponentFactory.RegisterComponentInstance(Of IDataProvider)(_DataProvider)
      16:              End If
      17:          End Sub
      19:          Public Sub New(ByVal dataprovider As IDataProvider)
      20:              _DataProvider = dataprovider
      21:          End Sub
  11. Now we need to create the IDataProvider interface.  Do this by changing the DataProvider class into an interface and removing the shared and static methods.  Then make the MustOverride functions into normal interface functions like so:
       1:      Public Interface IDataProvider
       3:          Function GetWebformsMVPs(ByVal ModuleId As Integer) As IDataReader
       4:          Function GetWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer) As IDataReader
       5:          Sub AddWebformsMVP(ByVal ModuleId As Integer, ByVal Content As String, ByVal UserId As Integer)
       6:          Sub UpdateWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer, ByVal Content As String, ByVal UserId As Integer)
       7:          Sub DeleteWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer)
       9:      End Interface
  12. Change the DataProvider file name to IDataProvider.
  13. Now we need to modify the SqlDataProvider class to use the new Interface.  Open the SqlDataProvider class and change the Inherits DataProvider to:
       1:      Public Class SqlDataProvider
       3:          Implements IDataProvider
  14. Add a private variable for the ModuleQualifier:
       1:  #Region "Private Members"
       3:          Private Const ModuleQualifier As String = "YourCompany_"
       5:  #End Region
  15. Next we need to change the ReadOnly properties so that we can set the values.  We need to be able to set the values so that during testing we can specify the values.  The code below will retrieve the value for the web.config file if it is not set.  This means during testing the value is set but in production the value comes from the config file.
       1:  #Region "Properties"
       2:          Private _connectionString As String = String.Empty
       3:          Public Property ConnectionString() As String
       4:              Set(ByVal value As String)
       5:                  _connectionString = value
       6:              End Set
       7:              Get
       8:                  If _connectionString = String.Empty Then
       9:                      Return DotNetNuke.Data.DataProvider.Instance().ConnectionString
      10:                  Else
      11:                      Return _connectionString
      12:                  End If
      13:              End Get
      14:          End Property
      16:          Private _databaseOwner As String
      17:          Public Property DatabaseOwner() As String
      18:              Set(ByVal value As String)
      19:                  _databaseOwner = value
      20:              End Set
      21:              Get
      22:                  If _databaseOwner = String.Empty Then
      23:                      Return DotNetNuke.Data.DataProvider.Instance().DatabaseOwner
      24:                  Else
      25:                      Return _databaseOwner
      26:                  End If
      27:              End Get
      28:          End Property
      30:          Private _objectQualifier As String
      31:          Public Property ObjectQualifier() As String
      32:              Set(ByVal value As String)
      33:                  _objectQualifier = value
      34:              End Set
      35:              Get
      36:                  If _objectQualifier = String.Empty Then
      37:                      Return DotNetNuke.Data.DataProvider.Instance().ObjectQualifier
      38:                  Else
      39:                      Return _objectQualifier
      40:                  End If
      41:              End Get
      42:          End Property
      44:  #End Region
  16. Remove the Overrides from each of the public methods and add the Implements to each one so that the IDataProvider interface is properly implemented:
       1:  #Region "Public Methods"
       3:          Public Function GetWebformsMVPs(ByVal ModuleId As Integer) _
       4:          As IDataReader Implements IDataProvider.GetWebformsMVPs
       5:              Return CType(SqlHelper.ExecuteReader(ConnectionString, _
       6:                     GetFullyQualifiedName("GetWebformsMVPs"), ModuleId), IDataReader)
       7:          End Function
       9:          Public Function GetWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer) _
      10:          As IDataReader Implements IDataProvider.GetWebformsMVP
      11:              Return CType(SqlHelper.ExecuteReader(ConnectionString, _
      12:                      GetFullyQualifiedName("GetWebformsMVP"), ModuleId, ItemId), IDataReader)
      13:          End Function
      15:          Public Sub AddWebformsMVP(ByVal ModuleId As Integer, ByVal Content As String, ByVal UserId As Integer) _
      16:          Implements IDataProvider.AddWebformsMVP
      17:              SqlHelper.ExecuteNonQuery(ConnectionString, _
      18:              GetFullyQualifiedName("AddWebformsMVP"), ModuleId, Content, UserId)
      19:          End Sub
      21:          Public Sub UpdateWebformsMVP(ByVal ModuleId As Integer, _
      22:                                       ByVal ItemId As Integer, ByVal Content As String, ByVal UserId As Integer) _
      23:          Implements IDataProvider.UpdateWebformsMVP
      24:              SqlHelper.ExecuteNonQuery(ConnectionString, _
      25:              GetFullyQualifiedName("UpdateWebformsMVP"), ModuleId, ItemId, Content, UserId)
      26:          End Sub
      28:          Public Sub DeleteWebformsMVP(ByVal ModuleId As Integer, ByVal ItemId As Integer) _
      29:          Implements IDataProvider.DeleteWebformsMVP
      30:              SqlHelper.ExecuteNonQuery(ConnectionString, _
      31:              GetFullyQualifiedName("DeleteWebformsMVP"), ModuleId, ItemId)
      32:          End Sub
      34:  #End Region
  17. Lastly in the Controller class change the DataProvider.Instance() to _DataProvider.
  18. Build your project now. 

Part 1 showed you how to modify the files from the starterkit ready to be able to test the SqlDataProvider and the Controller classes.  Part 2 will show you how to set up the classes required for using WebFormsMVP.


mohammad azarbara
in Q&A module a receive an error.
please help to fix it.
mohammad azarbara Saturday, September 28, 2013 9:31 AM (link)

Comment Form

Only registered users may post comments.


2sic Daniel Mettler (124)
Aderson Oliveira (15)
Alec Whittington (11)
Alex Shirley (10)
Andrew Nurse (30)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (21)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (203)
Chris Paterra (55)
Clinton Patterson (28)
Cuong Dang (21)
Daniel Bartholomew (2)
Dave Buckner (2)
David Poindexter (3)
David Rodriguez (2)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (74)
Geoff Barlow (6)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (269)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matthias Schlomann (15)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Mike Horton (19)
Mitchel Sellers (28)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Peter Donker (52)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott S (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (2)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (37)
Will Strohl (163)
William Severance (5)
Try Evoq
For Free
Start Free Trial
a Demo
See Evoq Live
Need More Information?