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.


Cambrian First Look - Extension Installer (Pt 3)

In my previous blog in this series I described how the new Extension Installer processes the manifest.  In summary the Installer creates an instance of a PackageInstaller and passes the manifest to it.  The PackageInstaller then parses the manifest and creates a ComponentInstaller for each component referenced in the manifest.  we sthus end up with the PackageInstaller having a collection (SortedList(Of T)) of ComponentInstallers.

Installing the Package

In this blog I will describe the next step in the process - Installing the Package.  As in my previous blog we will start in the Install wizard.

  292         Private Sub InstallPackage(ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs)

  293             CreateInstaller()

  294 

  295             If Installer.IsValid Then

  296                 'Reset Log

  297                 Installer.InstallerInfo.Log.Logs.Clear()

  298 

  299                 'Install

  300                 Installer.Install()

  301 

  302                 If Not Installer.IsValid Then

  303                     lblInstallMessage.Text = Localization.GetString("InstallError", LocalResourceFile)

  304                 End If

  305 

  306                 phInstallLogs.Controls.Add(Installer.InstallerInfo.Log.GetLogsTable)

  307             Else

  308                 'Error reading Manifest

  309                 Select Case e.CurrentStepIndex

  310                     Case 2

  311                         lblAcceptMessage.Text = Localization.GetString("InstallError", LocalResourceFile)

  312                         phAcceptLogs.Controls.Add(Installer.InstallerInfo.Log.GetLogsTable)

  313                     Case 3

  314                         lblInstallMessage.Text = Localization.GetString("InstallError", LocalResourceFile)

  315                         phInstallLogs.Controls.Add(Installer.InstallerInfo.Log.GetLogsTable)

  316                 End Select

  317                 e.Cancel = True

  318             End If

  319         End Sub

The InstallPackage method first creates the Installer (and parses the manfest).  As long as the manifest is valid, it clears the Logs and call the Install method of the Installer.  If the Install fails for any reason it displays a message to the user.  In both cases (success or failure) the Logs are displayed so the user can see the results of the install.

  325         Public Function Install() As Boolean

  326             InstallerInfo.Log.StartJob(Util.INSTALL_Start)

  327             Dim bStatus As Boolean = True

  328             Try

  329                 InstallPackages()

  330             Catch ex As Exception

  331                 InstallerInfo.Log.AddFailure(ex)

  332                 bStatus = False

  333             End Try

  334 

  335             If InstallerInfo.Log.Valid Then

  336                 InstallerInfo.Log.EndJob(Util.INSTALL_Success)

  337             Else

  338                 InstallerInfo.Log.EndJob(Util.INSTALL_Failed)

  339             End If

  340 

  341             ' log installation event

  342             LogInstallEvent("Package")

  343 

  344             'Clear Host Cache

  345             DataCache.ClearHostCache(True)

  346 

  347             Return bStatus

  348         End Function

The Install method attempts to install the packages(line 329), loggeing any exception that might occur.  The results of the installation are logged to the EventLog and the Host Cache is cleared.

  188         Private Sub InstallPackages()

  189             'Iterate through all the Packages

  190             For Each kvp As KeyValuePair(Of String, PackageInstaller) In Packages

  191                 'Check if package is valid

  192                 If kvp.Value.Package.IsValid Then

  193                     InstallerInfo.Log.AddInfo(Util.INSTALL_Start + " - " + kvp.Value.Package.Name)

  194                     kvp.Value.Install()

  195                     If InstallerInfo.Log.Valid Then

  196                         InstallerInfo.Log.AddInfo(Util.INSTALL_Success + " - " + kvp.Value.Package.Name)

  197                     Else

  198                         InstallerInfo.Log.AddInfo(Util.INSTALL_Failed + " - " + kvp.Value.Package.Name)

  199                     End If

  200                 Else

  201                     InstallerInfo.Log.AddFailure(Util.INSTALL_Aborted + " - " + kvp.Value.Package.Name)

  202                 End If

  203             Next

  204 

  205             'Delete Temp Folder

  206             If Not String.IsNullOrEmpty(TempInstallFolder) Then

  207                 Directory.Delete(TempInstallFolder, True)

  208             End If

  209             InstallerInfo.Log.AddInfo(Util.FOLDER_DeletedBackup)

  210         End Sub

The installPackages method iterates through the packages (Note: The Installer framework is setup to support the concept of multiple packages in a single manifest/zip.  However, the initial implementation of the Wizard only supports one package per manifest/zip).  For each Package, the method calls the PackageInstallers Install method.

  278         Public Overrides Sub Install()

  279             Dim isCompleted As Boolean = True

  280 

  281             Try

  282                 'Save the Package Information

  283                 If InstalledPackage IsNot Nothing Then

  284                     Package.PackageID = InstalledPackage.PackageID

  285                 End If

  286 

  287                 'Save Package

  288                 PackageController.SavePackage(Package)

  289 

  290                 'Iterate through all the Components

  291                 For index As Integer = 0 To ComponentInstallers.Count - 1

  292                     Dim compInstaller As ComponentInstallerBase = ComponentInstallers.Values(index)

  293                     If compInstaller.Version > Package.InstalledVersion Then

  294                         Log.AddInfo(Util.INSTALL_Start + " - " + compInstaller.Type)

  295                         compInstaller.Install()

  296                         If compInstaller.Completed Then

  297                             Log.AddInfo(Util.COMPONENT_Installed + " - " + compInstaller.Type)

  298                         Else

  299                             Log.AddFailure(Util.INSTALL_Failed + " - " + compInstaller.Type)

  300                             isCompleted = False

  301                             Exit For

  302                         End If

  303                     End If

  304                 Next

  305             Catch ex As Exception

  306                 Log.AddFailure(Util.INSTALL_Aborted + " - " + Package.Name)

  307             End Try

  308 

  309             If isCompleted Then

  310                 'All components successfully installed so Commit any pending changes

  311                 Commit()

  312             Else

  313                 'There has been a failure so Rollback

  314                 Rollback()

  315             End If

  316         End Sub

This method is the "hub" of the installation process.  The first part of the method (lines 282-288) determine whether we are dealing with an upgrade or a new install and save the Package level settings to the database.  Next, the method iterates through the ComponentInstallers collection.  Remember, this collection is a SortedList, and the loop processes the ComponentInstallers in order.  The loop checks if the componentInstaller's version is greater than the version of any previously installed package - we don't want to replace a version 2 component with a version 1 component.  If the new version is greater than any existing version, the PackageInstaller calls the ComponentInstallers Install method.  Once all the components have been installed, the isCompleted flag is checked to determine if any components failed to install.  If there was a failure, then the Rollback method is called, while if the installs all completed successfully the Commit method is called.  This provides a level of Transactional support.  If one component fails, an attempt is made to "undo" the changes that were successfully made in other components.

If we look at the Commit method

  256         Public Overrides Sub Commit()

  257             For index As Integer = 0 To ComponentInstallers.Count - 1

  258                 Dim compInstaller As ComponentInstallerBase = ComponentInstallers.Values(index)

  259                 If compInstaller.Version > Package.InstalledVersion AndAlso compInstaller.Completed Then

  260                     compInstaller.Commit()

  261                 End If

  262             Next

  263             If Log.Valid Then

  264                 Log.AddInfo(Util.INSTALL_Committed)

  265             Else

  266                 Log.AddFailure(Util.INSTALL_Aborted)

  267             End If

  268         End Sub

and the Rollback method

  429         Public Overrides Sub Rollback()

  430             For index As Integer = 0 To ComponentInstallers.Count - 1

  431                 Dim compInstaller As ComponentInstallerBase = ComponentInstallers.Values(index)

  432                 If compInstaller.Version > Package.InstalledVersion AndAlso compInstaller.Completed Then

  433                     Log.AddInfo(Util.COMPONENT_RollingBack + " - " + compInstaller.Type)

  434                     compInstaller.Rollback()

  435                     Log.AddInfo(Util.COMPONENT_RolledBack + " - " + compInstaller.Type)

  436                 End If

  437             Next

  438 

  439             'If Previously Installed Package exists then we need to update the DataStore with this

  440             If InstalledPackage Is Nothing Then

  441                 'No Previously Installed Package - Delete newly added Package

  442                 PackageController.DeletePackage(Package.PackageID)

  443             Else

  444                 'Previously Installed Package - Rollback to Previously Installed

  445                 PackageController.SavePackage(InstalledPackage)

  446             End If

  447         End Sub

we can see that both methods follow the same pattern as the Install method.  They iterate through the ComponentInstallers calling the relevant methods in these classes.

The advantage of this process is that the installation of each component type is delgated to a custom installer that knows how to handle the component.  Thus the install method of the AssemblyInstaller is very different from the Install method of a ConfigInstaller.  As we saw in the previous blog, this approach is also extensible.

Uninstalling an Extension works in much the same way as Installing, so we will get a Log of the Uninstall, both if the uninstall is a success or a failure.

I hope these last two blogs have given you an overview of how the process works.  Unless you actually need to create your own ComponentInstaller, you should not need to delve into this code in detail.  However, if you would like to take advantage of some of the new aspects of the Extension Installer, you will need to understand how to build a version 5 manifest, and I will delve into that aspect in more detail in my next blog on the subject.

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (15)
Alec Whittington (11)
Alex Shirley (10)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (32)
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 (209)
Chris Paterra (55)
Clinton Patterson (40)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (154)
Dave Buckner (2)
David Poindexter (4)
David Rodriguez (3)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (74)
Geoff Barlow (10)
George Alatrash (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 (274)
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)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (28)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
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)
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 (40)
Will Strohl (165)
William Severance (5)

Content Layout

Subscribe to DNN Digest

DNN Digest is our monthly email newsletter. It highlights news and content from around the DNN ecosystem, such as new modules and themes, messages from leadership, blog posts and notable tweets. Keep your finger on the pulse of the ecosystem by subscribing.  


Copyright 2017 by DNN Corp Terms of Use Privacy
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out