New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

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.

IPortable: Easily export content from your module to deploy on your production server

The IPortable interface will allow the users of your module to develop content on a development server and easily deploy this content to a production server. You will want to implement this interface in practically every module you create no matter how simple it is. The good news is that this task is very easy to do and does not require advanced programming or a significant amount of time.

What IPortable Will Do For You

Let's say you have a development server at your company and you created a survey using the Survey module (using the 04.00.00 or higher version. A link to the Beta is available at the end of this article).

You now want to put the Survey on your production server. To do so you would simply follow these steps:

1) From the menu of the Survey module select Export Content

2) Next, from the Export Module page click the Export button

3) While logged in as the portal Administrator select File Manger from the Admin menu

(do this while logged in as portal Administrator not as the portal Host using the Host account because you will not see the correct directory in the File Manager)

We see the .xml file that has been created (in this example content.Survey.Survey.xml)

4) Import the .xml file to your production server using these steps:

  • Log in as the Administrator of the portal
  • From the Admin menu select File Manger
  • In the File Manager click Upload
  • Browse to the location of the .xml file and after ensuring that Portal Root is selected in the location drop-down, click Upload New File

5) Next place an instance of the Survey module on a page (click here for directions on adding a module to a page) and from the Survey module's menu select Import Content

6) The .xml file is show in the drop-down. Click the Import button

And you're done!

Implementing IPortable

To implement this functionality in your own custom DotNetNuke module you simply:

  • Specify a business controller class in the module definition for the module
  • Add the line Implements Entities.Modules.IPortable in the business controller class
  • Create a ExportModule method and an ImportModule method

Specify a business controller class

The first thing you need to do is indicate a business controller class in the module definition for your module (If you have already started working on your module and you neglected to do this step initially you will have to delete the module definition and recreate it).

Here are the steps I used to create the module definition for the Survey module:

While logged into the DotNetNuke site as the "host" account, from the menu bar I selected Host and then selected Module Definitions

I clicked on the black arrow that is pointing down to make the fly-out menu to appear. On that menu I selected Add New Module Definition

In the Edit Module Definitions page I entered:

  • DNN_Survey for MODULE NAME
  • Survey for FOLDER TITLE
  • Survey for FRIENDLY TITLE
  • Survey allows you to create custom surveys to obtain public feedback for DESCRIPTION
  • 04.00.00 for VERSION
  • DotNetNuke.Modules.Survey.SurveyController for Controller Class

I then clicked UPDATE and completed the module definition (see my tutorial that describes how to create a module definition)

Add the Line Implements Entities.Modules.IPortable to the Business Controller Class

I created a SurveyController.vb class file

In that class I added the line Implements Entities.Modules.IPortable

Visual Studio then automatically adds the two stub methods.

Public Function ExportModule(ByVal ModuleID As Integer) As String Implements Entities.Modules.IPortable.ExportModule

End Function

Sub ImportModule(ByVal ModuleID As Integer, ByVal Content As String, ByVal Version As String, ByVal UserID As Integer) Implements _ Entities.Modules.IPortable.ImportModule


Create a ExportModule method

When the users of your module selects Export Content, the DotNetNuke framework will call the ExportModule method that you create and pass it a ModuleID parameter. It is expecting your method to return an .xml formatted response as a String data type.

When implementing this for the Survey module I can see that the Surveys are contained in the Surveys table, but the options (for example "First Choice") are contained in the SurveyOptions table.

For each Survey in the Surveys table, I will need to export the matching options for that survey in the SurveyOptions table. Another thing to notice is that while the primary key for the Surveys table is SurveyID, the field that is important right now is the ModuleID field. In the DotNetNuke architecture the ModuleID is an important parameter. A ModuleID represents a single instance of a module and is used to segment the data for each instance of that module in the database. A ModuleID is unique across all portals in a DotNetNuke installation.

Here is my implementation of the ExportModule method:

Public Function ExportModule(ByVal ModuleID As Integer) As String Implements DotNetNuke.Entities.Modules.IPortable.ExportModule

Dim strXML As New StringBuilder()
Dim settings As New XmlWriterSettings()
 settings.Indent =
settings.OmitXmlDeclaration = True
Writer As XmlWriter = XmlWriter.Create(strXML, settings)

 'Outer Loop - To build the Surveys
Dim colSurveys As List(Of SurveyInfo) = GetSurveys(ModuleID)
If colSurveys.Count > 0 Then
Dim SurveyInfo As SurveyInfo
For Each SurveyInfo In colSurveys
"question", SurveyInfo.Question)
"vieworder", SurveyInfo.ViewOrder)
"createdbyuser", SurveyInfo.CreatedByUser)
"createddate", SurveyInfo.CreatedDate)
"optiontype", SurveyInfo.OptionType.ToString)

     'Inner Loop - To build the Options for each Survey
    Dim colSurveyOptions As List(Of SurveyOptionInfo) = SurveyOptionController.GetSurveyOptions(SurveyInfo.SurveyId)
    If colSurveyOptions.Count > 0 Then
    Dim SurveyOptionInfo As SurveyOptionInfo
    For Each SurveyOptionInfo In colSurveyOptions
"optionname", SurveyOptionInfo.OptionName)
"iscorrect", SurveyOptionInfo.IsCorrect)
"vieworder", SurveyOptionInfo.ViewOrder)
    Next ' Retrieve the next SurveyOption
    End If
' There is nothing to export
Return String.Empty
End If


Here is a sample of the output created by the DotNetNuke framework from the output of this method:

<?xml version="1.0" encoding="utf-8" ?>
 <content type="Survey" version="04.00.00">
         <question><![CDATA[Question Number One]]></question>
         <createddate><![CDATA[9/3/2006 4:46:45 PM]]></createddate>
                 <optionname><![CDATA[First Choice]]></optionname>
                 <optionname><![CDATA[Second Choice]]></optionname>

Create a ImportModule method

When the users of your module select Import Content, the DotNetNuke framework will call the ImportModule method that you create and pass it a ModuleID parameter and a Content parameter as well as Version and UserID. It is expects your controller class to process the contents of the Content parameter which has a string data type. The Content parameter will contain the data in the form of the sample above. Your ImportModule method will not return anything. Your method will usually just insert the data passed to in in the Content parameter into the databse.

Here is my implementation of the ImportModule method:

Public Sub ImportModule(ByVal ModuleID As Integer, ByVal Content As String, ByVal Version As String, ByVal UserId As Integer) Implements DotNetNuke.Entities.Modules.IPortable.ImportModule

'Import the Surveys
'Outer Loop - To insert the Surveys
Dim intCurrentSurvey As Integer
xmlSurvey As XmlNode
Dim xmlSurveys As XmlNode = GetContent(Content, "surveys")
For Each xmlSurvey In xmlSurveys
Dim SurveyInfo As New SurveyInfo
SurveyInfo.ModuleId = ModuleID
SurveyInfo.Question = xmlSurvey.Item(
SurveyInfo.ViewOrder = xmlSurvey.Item(
SurveyInfo.CreatedByUser = xmlSurvey.Item(
SurveyInfo.CreatedDate = xmlSurvey.Item(
SurveyInfo.OptionType = xmlSurvey.Item(
'Add the Survey to the database
intCurrentSurvey = AddSurvey(SurveyInfo)

'Inner Loop - To insert the Survey Options
Dim xmlSurveyOption As XmlNode
Dim xmlSurveyOptions As XmlNode = xmlSurvey.SelectSingleNode("surveyoptions")
For Each xmlSurveyOption In xmlSurveyOptions
Dim SurveyOptionInfo As New SurveyOptionInfo
SurveyOptionInfo.SurveyId = intCurrentSurvey
SurveyOptionInfo.OptionName = xmlSurveyOption.Item(
SurveyOptionInfo.IsCorrect = xmlSurveyOption.Item(
SurveyOptionInfo.ViewOrder = xmlSurveyOption.Item(
'Add the Survey to the database

' Retrieve the next Survey

End Sub

That's it. You're done.

It is not a lot of code, yet the functionality that this creates for the end user is significant.

Hopefully you will find this example helpful because if you examine the code you will see that I had to insert a survey, retrieve the SurveyID and then use that SurveyID when inserting the matching survey options.

This interface represents another example of why you would choose to use the DotNetNuke framework for a project rather than coding the project completely from scratch. By simply creating two simple methods you can provide your project with a process to move content between servers. Unlike the sometimes awkward and error prone methods of direct data transfer, you will have .xml files that can be easily backed up and versioned.  Most importantly the data is separated from the content (for example the survey results are not exported just the surveys). In addition you have complete control over what defines content.

In future postings I will cover other Interfaces that are important to module developers such as IActionable and ISearchable,

The Survey code covered above is BETA and has not been released. You can download the code using this link. Before you upload it to an existing DNN4 site you have to remove these two assemblies from the "\bin" directory of your existing DNN site.


There are currently no comments, be the first to post one.

Comment Form

Only registered users may post comments.


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Davies (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
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 (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (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)
Steven Fisher (1)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out