DotNetNuke 4.9.1 and DotNetNuke 5.0 included a new feature called the DotNetNuke Dashboard which is available from the Host menu.  The Dashboard provides access to numerous stats and settings from a single location which simplifies finding the information which is often needed when troubleshooting problems.

In addition to displaying critical data, the Dashboard allows the host user to export the data so that it can be easily provided to tech support if desired.  Having offered SLA support for the past year, DotNetNuke Corp staff often had to do much of this data collection using manual processes.  In speaking with many module vendors, we found that they were experiencing the same support issues.  The dashboard should greatly simplify this process.

Dashboard

I believe the most exciting feature of the Dashboard is not the out of box stats and settings that it displays, but the fact that the dashboard is customizable and extensible.  Every page in the dashboard can be removed or replaced (in the current version this requires a little SQL).  In addition, developers are able to add their own pages to the dashboard.  This would allow you to have a central location for getting a simple health snapshot.

Adding your own pages to the Dashboard is pretty simple, although there are a couple little things you need to look out for.  So let’s jump in with a sample Dashboard extension.

For our first extension, we’re going to show a list of AppSettings which are stored in web.config.  We’ll do a simple filter to remove the legacy connection string which may contain very sensitive data.  Below is a picture of how our finished page should look.

DashboardAppSettings

The first step is to create a simple webcontrol that inherits from PortalModuleBase.  We’ll use a simple repeater to display the settings:

<%@ Control Language="vb" 
    Inherits="DotNetNukeCorp.Modules.Dashboard.AppSettings.ViewAppSettings"
    CodeFile="ViewAppSettings.ascx.vb" 
    AutoEventWireup="false" 
    Explicit="True" %>
<%@ Register TagPrefix="dnn" TagName="Label" Src="~/controls/LabelControl.ascx" %>

<dnn:Label id="plAppSettings" runat="Server" CssClass="Head" ControlName="webSettings" />
<asp:Repeater ID="webSettings" runat="server">
    <HeaderTemplate>
        <table cellspacing="0" border="0" style="border-collapse: collapse;">
        <tr>
            <th scope="col">Setting Name</th>
            <th scope="col">Value</th>
        </tr>
    </HeaderTemplate>
    <ItemTemplate>
        <tr>
            <td><%#Eval("Name")%></td>
            <td><%#Eval("Value")%></td>
        </tr>
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:Repeater>

Wiring up the repeater is also pretty simple.  Our AppSettingsController class provides a GetSettings method which returns a List of SettingsInfo objects which we can assign directly to the repeater. 

Imports DotNetNuke
Imports DotNetNukeCorp.Modules.Dashboard.Components.AppSettings

Namespace DotNetNukeCorp.Modules.Dashboard.AppSettings

    Partial Class ViewAppSettings
        Inherits Entities.Modules.PortalModuleBase

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If UserInfo.IsSuperUser Then
                webSettings.DataSource = AppSettingsController.GetSettings()
                webSettings.DataBind()
            End If
        End Sub
    End Class

End Namespace

The controller class is likewise pretty simple.  It implements a single business method to get the settings and a single method to serialize the settings.  Notice that we implement the IDashboardData interface which defines the ExportData method.  This method is needed if you want your data serialized when the Dashboard exports its data.  You are in complete control of the XML format.  In this sample I am using a simple XMLSerializer to handle the heavy lifting, but it would have been just as easy to manually loop through the records and create the XML.  Do not feel constrained to use a serializer which is probably overkill in most cases.  I only use it here for brevity and simplicity.

Imports System
Imports System.Configuration
Imports System.Collections.Generic
Imports DotNetNuke.Modules.Dashboard.Components
Imports System.Xml.Serialization

Namespace DotNetNukeCorp.Modules.Dashboard.Components.AppSettings

    Public Class AppSettingsController
        Implements IDashboardData

#Region "Public Methods"

        Public Shared Function GetSettings() As List(Of SettingsInfo)

            Dim settings As NameValueCollection = ConfigurationManager.AppSettings
            Dim filteredSettings As New List(Of SettingsInfo)
            For Each name As String In settings.Keys
                'We should do more filtering to keep out connection strings.
                If name <> "SiteSqlServer" Then
                    filteredSettings.Add(New SettingsInfo(name, settings(name)))
                End If
            Next
            Return filteredSettings

        End Function

        Public Sub ExportData(ByVal writer As System.Xml.XmlWriter) Implements DotNetNuke.Modules.Dashboard.Components.IDashboardData.ExportData
            Dim websettings As List(Of SettingsInfo) = GetSettings()
            Dim ser As XmlSerializer = New XmlSerializer(GetType(List(Of SettingsInfo)))
            ser.Serialize(writer, websettings)
        End Sub

#End Region

    End Class
End Namespace

The SettingsInfo class is a simple class with Name and Value properties which we won’t show here for the sake of brevity.  With all of our code done, it is now time to turn our attention to our SQL. 

The Dashboard requires the use of the localization framework for retrieving the name to be displayed in the page list.  The Title setting is mandatory and must be named using the DashboardControlKey stored in the database.

DashBoard_LocalResources

Our first iteration of the Dashboard does not include the business layer for adding new pages so we’ll do it at the database level for now.  Just remember that this is likely to change in the next version so don’t get used to modifying the data records directly.  Below is the SQLDataProvider script we use to add our new page to the Dashboard.

INSERT INTO {databaseOwner}[{objectQualifier}Dashboard_Controls] 
    ([DashboardControlKey],
    [IsEnabled],
    [DashboardControlSrc],
    [DashboardControlLocalResources],
    [ControllerClass],
    [ViewOrder]) 
VALUES 
    (N'AppSettings', 
    1, 
    N'DesktopModules/DashboardAppsettings/ViewAppSettings.ascx', 
    N'DesktopModules/DashboardAppsettings/App_LocalResources/ViewAppSettings.ascx', 
    N'DotNetNukeCorp.Modules.Dashboard.Components.AppSettings.AppSettingsController', 
    7)

GO

This updates the dashboard_controls table with our new page which is now ready to be displayed.

Once you have the extension built, you have to figure out how to distribute the extension.  The easiest way to do so, is to add the extension as part of a module.  This provides a natural place for hosting the sql script and installing the necessary control.  This also makes it easy to install in both 4.9.1 and 5.0.0.  If however, you just want to create a simple extension like I have done here, then you can also create a standalone package.  Unfortunately, DNN 4.9.1 does not include full installer support so there are some hoops you have to jump through.  I have package this up as a “Library” package which can be installed from the Authentication Provider installation screen in DNN 4.9.1.  You can reach this page directly at ~/tabid/16/ctl/Install/portalid/0/Default.aspx.  You may need to adjust the portalid and tabid values for your site.

 

You can download a working version of this project from CodePlex: DotNetNuke Dashboard AppSettings project.