Products

Solutions

Resources

Partners

Community

About

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.


7.0 Installer–Inside Scoop (2/2)

PortMannFuturustic

This blog is a continuation of my previous blog on the topic of Challenges in Installer Implementation and how team resolved them. Above is a futuristic picture of the Port Mann Bridge when finished. It’s copied from Bridge's page. Check my previous blog for why I chose this picture Smile

Once settled on the appearance and actions of the Progressbar we had to look for the backend calls.

Backend Calls

Services Framework

I was counting heavily on our shiny new Service Framework (SF). Turned out that wasn’t easly accessible to the Installer. Why? Initialization of the service routes dependent on something that wasn’t available during Installation. We have a flag in the DotNetNuke framework where we check for installation status and skip many actions if the framework has not been fully installed. We could have tinkered with bits here and there to make SF available during Installation, but that would have resulted in unnecessary overhead with a corresponding increase in installation time – the opposite of our goals for the new Installer

So much for a Progressbar, eh?

What now?

WebMethod

Turns out that Asp.Net has a little known Ajax method called as WebMethod. Webmethod provides easily callable APIs from the web client without the need for web services, wcf or mvc. That turned out to be actually pretty simple to use.

Code Behind

[System.Web.Services.WebMethod]
public static void RunInstall()
{
    LaunchAutoInstall();
}

Client Side

//Call PageMethod which triggers long running operation
PageMethods.RunInstall(function () {
}, function (err) {
    $.stopProgressbarOnError();
});

If you are interested in finding sample code around use of WebMethod, you can find in /Install/InstallWizard.aspx and InstallWizard.aspx.cs here on our codeplex source repository.

Url Checks

We have a number of places in the framework where we check for special URLs and skip processing if they are Installwizard.aspx, UpgradeWizard.aspx, etc.

Old Code

//First check if we are upgrading/installing
if (app.Request.Url.LocalPath.ToLower().EndsWith("install.aspx")
|| app.Request.Url.LocalPath.ToLower().EndsWith("upgradewizard.aspx")
|| app.Request.Url.LocalPath.ToLower().EndsWith("installwizard.aspx")
|| app.Request.Url.LocalPath.ToLower().EndsWith("captcha.aspx")

One problem with using WebMethods was that it appends the method name in the URL. Most of the above checks failed as we were using "EndsWith" in a string comparison. WebMethod actually changed the URL from installwizard.aspx to installwizard.aspx?RunInstall. (Note the extra parameter.) The fix was pretty simple, but we were thrown for a loop as this check was being done in a number of places and it took a while to narrow them all. Once located, we had to change each EndsWith to Contains.

Changed Code

//First check if we are upgrading/installing
if (app.Request.Url.LocalPath.ToLower().EndsWith("install.aspx")
|| app.Request.Url.LocalPath.ToLower().Contains("upgradewizard.aspx")
|| app.Request.Url.LocalPath.ToLower().Contains("installwizard.aspx")
|| app.Request.Url.LocalPath.ToLower().EndsWith("captcha.aspx")

Client Polling

In order to show progress we needed a mechanism to poll status from server frequently. The main installation thread could not be used as it takes a while to finish. We therefore decided to create other WebMethod calls. Not a big deal; just more work

A new WebMethod was quickly createdto get the Progress percentage and Milestone status. This call gets executed from the client side every second. Here comes the tricky part yet again, the code-behind initiallt used static variables to store current status of the Install. Everything was fine up until Installer restarted. As mentioned above, Installer makes many changes as it runs, and one of the changes is the update of web.config. This causes App Restarts.

App Restarts

App Restarts aren’t aren't evil as they sound :-) The good news was that the main thread kept running even after the app start. It actually did everything that it was supposed to do before terminating gracefully. One good thing to cheer about IIS is that it keeps the older w3wp.exe process running as long as old threads are still running. However, should a new request come during this time, IIS would launch a new instance of w3wp to serve new requests.

As soon as the App gets into restart situation, the very next client polling request causes a new w3wp.exe to fire up. No problem, everything was as expected. After all, the firing of a new App is pretty standard in IIS. However, all of our static variables to store Installer status in the original thread were no longer available in the process. We were hoping that the counters from original thread would be available to the polling thread throughout the Installation. That wasn't the case though. It maintained the counters till only about 80% of Instllation. What now? It’s like we were all ready for lift-off and then we ran into another snag

Inter Process Communication

Coming from a C++ background I am extremely familiar with the Inter Process Communication (IPC) tools available in Win32 APIs; mutex, events, named pipes, memory mapped files are a few that comes to mind. I must also say that none of them are actually suitable for a web application. Database was one option, but it wasn’t guaranteed to be available at the time of installation.

Alas, the old-school text file came to the rescue. The main installation thread stores status as a serialized JSON object in a known text file under \Portals\_Default\Logs folder and the Polling callbacks reads that. Since installation is a pretty fast moving vehicle ( writing to this intermediate log file very frequently), we added try-catch logic around reads and writes to make sure nothing gets locked-up or that we don't throw unnecessary errors.

Hope the above blog and one prior provides great insight on some of the challenges our Engineering team encountered during creation of Installer in 7.0, and best how we tackled them.

  • Published:

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (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)
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