Select the search type
  • Site
  • Web
Search
You are here:  Company/News

Blog2mind

SysInfo solution to improve DNN support

Some of you will recognize this. A recurring pattern in DNN module support is to find out what the customer has running in the first place. Not just your own module (i.e. version), but also ‘the bigger picture’. There are ‘expert’ customers that will write you this in a first email, and there are those that have no clue what you’re asking them. Luckily most of my customers fall toward the expert category. Despite this I still spend a lot of time (emails back and forth) determining the client system. And regularly I have to ‘talk the customer through’ how to get those bits of information that are relevant to me (e.g. is Ajax enabled? Are you using compression? Do you have dll XYZ installed?)

This post is about a solution I’ve been working on. The aim is to let a superuser hit a button and he/she receives a file with all the relevant bits of info I might need. The solution could come in the form of a module (which is how I developed it), but IMO this is not going to be very successful. You need the functionality only when you get stuck with something. And typically people would resist installing modules unnecessarily (I think this is a ‘good’ tendency as you never know what you drag inside of your DNN installation). So my goal is to lift this into the DNN core one day.

The Solution

So what does the current solution (called SysInfo for now) look like? Well, it’s a linkbutton that instantiates a class (called XmlReport for lack of a better name right now) that inherits from XmlDocument. This class builds all the info within itself and the containing module tells it to render itself to the output stream. All this is pretty straightforward stuff.

I have tried to split off as much generic stuff into static methods in a Common class. This allows others to use that class. Why is this useful? Well, the object is that through an interface in the business controller class other modules can add to the report as well. So my document management module could tell something about its configuration. Now that would be neat IMO. Click the magic button and you get an XML report of the core configuration and specifics for any module.

Public Interface ISysInfoProducer

 Sub ProduceInfo(ByRef node As XmlNode)

End Interface


The XmlReport class goes through all the installed modules, checks the Business Controller class and if it support this interface, it will be called with the root node of the report as argument. Below you’ll find the other two main classes I mentioned before.

What can you do?

Vote for this enhancement. I have submitted it to the enhancement request section of DNN:

http://www.dotnetnuke.com/Products/Development/Roadmap/tabid/616/ctl/Details/mid/3582/enhancementid/175/Default.aspx

Vote for it and it might be included one day.

Common.vb

Public Class Common

 

#Region " Generic Data "

 Public Shared Sub RunQuery(ByRef node As XmlNode, ByVal tableName As String, ByVal rowName As String, ByVal query As String)

  If node Is Nothing Then Exit Sub

  AddDataReader(node, tableName, rowName, DotNetNuke.Data.DataProvider.Instance.ExecuteSQL(query))

 End Sub

 

 Public Shared Sub AddDataReader(ByRef node As XmlNode, ByVal tableName As String, ByVal rowName As String, ByVal reader As IDataReader)

  If node Is Nothing Then Exit Sub

  Dim table As XmlNode = node.OwnerDocument.CreateElement(tableName)

  node.AppendChild(table)

  Dim fields As New ArrayList

  Dim intFieldCount As Integer = reader.FieldCount

  Dim intCounter As Integer

  For intCounter = 0 To intFieldCount - 1

   fields.Add(reader.GetName(intCounter))

  Next intCounter

  While reader.Read()

   Dim row As XmlNode = node.OwnerDocument.CreateElement(rowName)

   table.AppendChild(row)

   For Each field As String In fields

    AddElement(row, field, GetAString(reader.Item(field)))

   Next

  End While

  reader.Close()

 End Sub

 

 Public Shared Function GetAString(ByVal x As Object) As String

  If x Is Nothing Then

   Return "NULL"

  ElseIf x Is DBNull.Value Then

   Return "NULL"

  Else

   Return Convert.ToString(x)

  End If

 End Function

#End Region

 

#Region " File System "

 Public Shared Sub AddFileSystemDetails(ByRef node As XmlNode, ByVal path As String, ByVal includeFiles As Boolean, ByVal recurse As Boolean)

  If node Is Nothing Then Exit Sub

  Dim x As XmlNode = node.OwnerDocument.CreateElement("Folder")

  node.AppendChild(x)

  AddAttribute(x, "Path", path)

  If Not VerifyFileCreate(path & "\Verify.txt") Then

   AddAttribute(x, "VerifyFileCreate", "False")

  End If

  If Not VerifyFileCreate(path & "\Verify.txt") Then

   AddAttribute(x, "VerifyFileDelete", "False")

  End If

  If Not VerifyFolderCreate(path & "\Verify") Then

   AddAttribute(x, "VerifyFolderCreate", "False")

  End If

  If Not VerifyFolderDelete(path & "\Verify") Then

   AddAttribute(x, "VerifyFolderDelete", "False")

  End If

  AddAttribute(x, "Files", IO.Directory.GetFiles(path).Length.ToString)

  If includeFiles Then

   For Each f As String In IO.Directory.GetFiles(path)

    Dim fi As New IO.FileInfo(f)

    Dim xFile As XmlNode = node.OwnerDocument.CreateElement("File")

    x.AppendChild(xFile)

    xFile.InnerText = fi.Name

    AddAttribute(xFile, "Size", fi.Length.ToString)

    AddAttribute(xFile, "CreationTime", fi.CreationTime.ToString("u"))

    If f.EndsWith(".dll") Then

     Try

      Dim ass As System.Reflection.Assembly = System.Reflection.Assembly.LoadFile(f)

      AddAttribute(xFile, "AssemblyVersion", ass.GetName.Version.ToString)

      AddAttribute(xFile, "FileVersion", System.Diagnostics.FileVersionInfo.GetVersionInfo(ass.Location).FileVersion)

      AddAttribute(xFile, "CompanyName", System.Diagnostics.FileVersionInfo.GetVersionInfo(ass.Location).CompanyName)

      AddAttribute(xFile, "ProductVersion", System.Diagnostics.FileVersionInfo.GetVersionInfo(ass.Location).ProductVersion)

      AddAttribute(xFile, "ProductName", System.Diagnostics.FileVersionInfo.GetVersionInfo(ass.Location).ProductName)

     Catch ex As Exception

     End Try

    End If

   Next

  End If

  If recurse Then

   For Each sDir As String In IO.Directory.GetDirectories(path)

    AddFileSystemDetails(x, sDir, includeFiles, recurse)

   Next

  End If

 End Sub

 

 Public Shared Function VerifyFileCreate(ByVal verifyFilePath As String) As Boolean

  Dim verified As Boolean = True

  'Attempt to create the File

  Try

   If IO.File.Exists(verifyFilePath) Then

    IO.File.Delete(verifyFilePath)

   End If

   Dim fileStream As IO.Stream = IO.File.Create(verifyFilePath)

   fileStream.Close()

  Catch ex As Exception

   verified = False

  End Try

  Return verified

 End Function

 

 Public Shared Function VerifyFileDelete(ByVal verifyFilePath As String) As Boolean

  Dim verified As Boolean = True

  'Attempt to delete the File

  Try

   IO.File.Delete(verifyFilePath)

  Catch ex As Exception

   verified = False

  End Try

  Return verified

 End Function

 

 Public Shared Function VerifyFolderCreate(ByVal verifyPath As String) As Boolean

  Dim verified As Boolean = True

  'Attempt to create the Directory

  Try

   If IO.Directory.Exists(verifyPath) Then

    IO.Directory.Delete(verifyPath, True)

   End If

   IO.Directory.CreateDirectory(verifyPath)

  Catch ex As Exception

   verified = False

  End Try

  Return verified

 End Function

 

 Public Shared Function VerifyFolderDelete(ByVal verifyPath As String) As Boolean

  Dim verified As Boolean = True

  If verified Then

   'Attempt to delete the Directory

   Try

    IO.Directory.Delete(verifyPath)

   Catch ex As Exception

    verified = False

   End Try

  End If

  Return verified

 End Function

#End Region

 

#Region " Add Xml Files "

 Public Shared Sub AddXmlFile(ByRef node As XmlNode, ByVal nodeName As String, ByVal filename As String)

  If node Is Nothing Then Exit Sub

  AddXmlFile(node, nodeName, filename, "", "")

 End Sub

 

 Public Shared Sub AddXmlFile(ByRef node As XmlNode, ByVal nodeName As String, ByVal filename As String, ByVal grepReplace As String, ByVal grepReplaceWith As String)

  If node Is Nothing Then Exit Sub

  Dim xmld As New XmlDocument

  xmld.Load(filename)

  Dim x As XmlNode = node.OwnerDocument.CreateElement(nodeName)

  node.AppendChild(x)

  If grepReplace = "" Then

   x.InnerXml = xmld.DocumentElement.InnerXml

  Else

   x.InnerXml = Regex.Replace(xmld.DocumentElement.InnerXml, grepReplace, grepReplaceWith)

  End If

 End Sub

#End Region

 

#Region " Host Settings "

 Public Shared Sub AddHostSettings(ByRef node As XmlNode)

  If node Is Nothing Then Exit Sub

  Dim host As XmlNode = node.OwnerDocument.CreateElement("Host")

  node.AppendChild(host)

  AddElement(host, "AppVersion", glbAppVersion)

  AddElement(host, "DataProvider", Providers.ProviderConfiguration.GetProviderConfiguration("data").DefaultProvider)

  AddElement(host, "Framework", System.Environment.Version.ToString)

  AddElement(host, "MachineName", System.Environment.MachineName)

  AddElement(host, "Platform", System.Environment.OSVersion.Platform.ToString)

  AddElement(host, "PlatformVersion", System.Environment.OSVersion.Version.ToString)

  AddElement(host, "ProcessorCount", System.Environment.ProcessorCount.ToString)

  AddElement(host, "UserDomainName", System.Environment.UserDomainName)

  AddElement(host, "WorkingSet", System.Environment.WorkingSet.ToString)

  AddElement(host, "Identity", System.Security.Principal.WindowsIdentity.GetCurrent.Name)

  AddElement(host, "HostName", Net.Dns.GetHostName())

  Dim strPermissions As String = ""

  If Framework.SecurityPolicy.HasRelectionPermission Then

   strPermissions += ", " & Framework.SecurityPolicy.ReflectionPermission

  End If

  If Framework.SecurityPolicy.HasWebPermission Then

   strPermissions += ", " & Framework.SecurityPolicy.WebPermission

  End If

  AddElement(host, "Permissions", Mid(strPermissions, 3))

  AddElement(host, "ApplicationPath", DotNetNuke.Common.ApplicationPath)

  AddElement(host, "ApplicationMapPath", DotNetNuke.Common.ApplicationMapPath)

  AddElement(host, "WebFarmEnabled", DotNetNuke.Common.Globals.WebFarmEnabled.ToString())

  AddHostSetting(host, "GUID", "HostPortalId", "HostTitle", "HostURL", "HostEmail", "ControlPanel")

  AddHostSetting(host, "PaymentProcessor", "Currency", "HostCurrency")

  AddHostSetting(host, "SchedulerMode", "HostSpace", "PageQuota", "UserQuota")

  AddHostSetting(host, "SiteLogStorage", "SiteLogBuffer", "SiteLogHistory")

  AddHostSetting(host, "PageStatePersister", "ModuleCaching", "PerformanceSetting", "AuthenticatedCacheability", "HttpCompression", "WhitespaceFilter")

  AddHostSetting(host, "DemoPeriod", "DemoSignup", "Copyright", "DisableUsersOnline", "UsersOnlineTime", "EnableAJAX")

  AddHostSetting(host, "AutoAccountUnlockDuration", "ProxyServer", "ProxyPort", "WebRequestTimeout")

  AddElement(host, "SMTPServerSet", (Convert.ToString(DotNetNuke.Common.Globals.HostSettings("SMTPServer")) <> "").ToString)

  AddHostSetting(host, "SMTPAuthentication", "SMTPEnableSSL")

  AddHostSetting(host, "FileExtensions", "UseCustomErrorMessages", "UseFriendlyUrls", "EnableRequestFilters")

  AddHostSetting(host, "EventLogBuffer", "SkinUpload", "HelpURL", "EnableModuleOnLineHelp", "EnableFileAutoSync")

 End Sub

 

 Public Shared Sub AddHostSetting(ByRef node As XmlNode, ByVal ParamArray settings() As String)

  For Each setting In settings

   If DotNetNuke.Common.Globals.HostSettings(setting) IsNot Nothing Then

    AddElement(node, setting, Convert.ToString(DotNetNuke.Common.Globals.HostSettings(setting).ToString))

   End If

  Next

 End Sub

#End Region

 

#Region " Helper Methods "

 Public Shared Sub AddAttribute(ByRef node As XmlNode, ByVal propName As String, ByVal propValue As String)

  If node Is Nothing Then Exit Sub

  Dim att As XmlAttribute = node.OwnerDocument.CreateAttribute(propName)

  att.InnerText = propValue

  node.Attributes.Append(att)

 End Sub

 

 Public Shared Sub AddElement(ByRef node As XmlNode, ByVal propName As String, ByVal propValue As String)

  If node Is Nothing Then Exit Sub

  Dim elt As XmlNode = node.OwnerDocument.CreateElement(propName)

  elt.InnerText = propValue

  node.AppendChild(elt)

 End Sub

#End Region

 

End Class

 

XmlReport.vb

Public Class XmlReport

 Inherits XmlDocument

 

#Region " Private Members "

 Private _root As XmlNode

 Private _dataProvider As String = "SqlDataProvider"

#End Region

 

#Region " Constructors "

 Public Sub New()

  MyBase.New()

  Me.AppendChild(Me.CreateXmlDeclaration("1.0", Nothing, "yes"))

  _root = Me.CreateElement("Report")

  _dataProvider = Providers.ProviderConfiguration.GetProviderConfiguration("data").DefaultProvider

  Me.AppendChild(_root)

  AddAttribute(_root, "Created", Now.ToString("u"))

  AddHostSettings(_root)

  AddXmlFile(_root, "Compression", DotNetNuke.Common.Globals.ApplicationMapPath + "\Compression.config")

  AddXmlFile(_root, "WebConfig", DotNetNuke.Common.Globals.ApplicationMapPath + "\web.config", "(?i)(?<=validationkey=""|decryptionkey=""|key=""sitesqlserver"" value=""|connectionstring="")[^""]+(?-i)", "*******")

  Dim x As XmlNode = Me.CreateElement("FileSystem")

  _root.AppendChild(x)

  AddFileSystemDetails(x, DotNetNuke.Common.ApplicationMapPath & "\bin", True, False)

  AddFileSystemDetails(x, DotNetNuke.Common.ApplicationMapPath & "\portals", False, True)

  AddDataReader(_root, "InstalledModules", "Module", DotNetNuke.Data.DataProvider.Instance.GetDesktopModules)

  If _dataProvider.ToLower = "sqldataprovider" Then

   RunQuery(_root, "Portals", "Portal", "SELECT p.*, (SELECT COUNT(*) FROM {objectQualifier}Users u INNER JOIN {objectQualifier}UserPortals up ON u.UserId=up.UserId WHERE up.PortalId=p.PortalId) AS NrUsers, (SELECT COUNT(*) FROM {objectQualifier}Tabs t WHERE t.PortalID=p.PortalID) AS NrTabs FROM {objectQualifier}Portals p")

   For Each pi As Portals.PortalInfo In (New Portals.PortalController).GetPortals

    AddDataReader(_root.SelectSingleNode("Portals/Portal"), "Aliases", "Alias", DotNetNuke.Data.DataProvider.Instance.GetPortalAliasByPortalID(pi.PortalID))

   Next

  End If

  For Each dm As DotNetNuke.Entities.Modules.DesktopModuleInfo In (New DotNetNuke.Entities.Modules.DesktopModuleController).GetDesktopModules

   If dm.BusinessControllerClass <> "" Then

    Try

     Dim objController As Object = Framework.Reflection.CreateObject(dm.BusinessControllerClass, "")

     If TypeOf objController Is ISysInfoProducer Then

      Dim sip As ISysInfoProducer = CType(objController, ISysInfoProducer)

      sip.ProduceInfo(_root)

     End If

    Catch ex As Exception

    End Try

   End If

  Next

 End Sub

#End Region

 

 

End Class

 

Archive