Feb 5

Written by: Michael Washington
2/5/2017 2:45 PM  RssIcon

The DotNetNuke project demonstrates how you can use a set-up wizard that works in a lot of situations. This allows you to FTP an application to a remote server and then launch a configuration wizard from the web browser. This can also be used, instead of Code First Migrations, to upgrade the database for developers when they pull down the latest code changes to their local machines.

This example consists of an Angular C# Visual Studio project using ASP.NET 4 MVC and OData 4. The Angular 2+ code is written in TypeScript.

Set-up The Application

image

The first step is to create a database using SQL Server.

image

Next, download the project from the downloads page on this site, and unzip the file.

image

Open the project using Visual Studio 2015 (or higher) by opening the WebBasedInstaller.sln file.

Note: You can download the free Visual Studio 2015 Community Edition from: https://www.visualstudio.com/downloads/download-visual-studio-vs.

image

In Visual Studio, select Debug, then Start Debugging, to run the project.

image

The project will open in your web browser.

Because the project is not set-up yet, the Install Wizard will display.

Enter the information to connect to the database and click Set Connection.

This will update the web.config file with the database connection string.

image

The next screen asks you to create an administrator account.

image

At this point the minimal database tables have been created.

To proceed, you will have to log in using the Administrator account you just created.

Any scripts past the initial set-up scripts will always trigger this log in page.

image

At this step, any additional install scripts will run.

When they are complete, the Continue button will show.

image

When the application detects that the database is set-up and that all required set-up and update scripts have run, the application will show.

If you stop and re-start the project at this point, it will go directly to the application.

Prime NG

image

This sample project makes extensive use of the free open source PrimeNG Angular 2 components.

How To Set-Up An Upgrade

image

The project allows you to trigger the Install Wizard to upgrade the database by simply adding a new .sql file to the !SQLScripts folder…

image

… and setting the TargetDatabaseVersion in the OData4Controller.cs file.

This is normally done when a new version of the code, that requires the database upgrade, is released.

The following server side method performs the upgrades needed:

 

public IHttpActionResult UpdateDatabase()
    {
        DTOStatus objDTOStatus = new DTOStatus();
        if (this.User.Identity.IsAuthenticated &&
            this.User.IsInRole("Administrator"))
        {
            InstallWizardEntities db = new InstallWizardEntities();
            objDTOStatus.StatusMessage = "";
            objDTOStatus.Success = true;
            // Get the update scripts
            List<string> ColScripts = UpdateScripts();
            foreach (var sqlScript in ColScripts)
            {
                try
                {
                    // Run the script
                    db.Database.ExecuteSqlCommand(GetSQLScript(sqlScript));
                }
                catch (Exception ex)
                {
                    objDTOStatus.StatusMessage = ex.Message;
                    objDTOStatus.Success = false;
                    return Ok(objDTOStatus);
                }
            }
        }
        else
        {
            objDTOStatus.StatusMessage = "Not an authenticated Administrator";
            objDTOStatus.Success = false;
        }
        // Return the result            
        return Ok(objDTOStatus);
    }

 

Detect That The Database Is Not Set-Up

image

The code for the Angular application is contained in the app folder.

The code for the Install Wizard is primarily contained in the InstallWizard.component.ts file with the InstallWizard.component.html file containing the visual markup.

The following Angular method, detects if the database is fully set up and updated. If it is, it navigates to the products page, otherwise it invokes the wizard:

 

    getDatabaseStatus() {
        // Call the service to get the current database status
        // if isNewDatabase is returned it means version table does not exist
        this._installWizardService.getCurrentVersion().subscribe(
            version => {
                this.version = version;
                if (this.version.isNewDatabase) {
                    // The database is not set up
                    this.setActvePanel(panelType.DatabaseConfiguration);
                }
                else {
                    // The database is set up
                    if (this.version.isUpToDate) {
                        // Everything is set up
                        // Show the Products application
                        this._router.navigateByUrl('/products');
                    }
                    else {
                        // Administrator must log in to continue
                        this.setActvePanel(panelType.AdministratorLogin);
                    }
                }
            },
            error => this.errorMessage = <any>error);
    }

 

Set Database Connection

image

If the database is not set-up, the Database Configuration panel shows.

When the user has entered the required information, they click the Set Connection button and the following code is invoked:

 

    setConnection() {    
        this.errorMessage = "";
        // Create a ConnectionSettings object
        let ConnectionSetting: IConnectionSetting = {
            DatabaseName: this.DatabaseName,
            ServerName: this.ServerName,
            IntegratedSecurity: this.IntegratedSecurity,
            Username: this.Username,
            Password: this.Password
        }
        // Call the service 
        this._installWizardService.setConnection(ConnectionSetting).subscribe(
            response => {
                this.DatabaseConnectionMessage = response; 
                if (this.DatabaseConnectionMessage == "Success") {
                    // Move to the next step
                    this.setActvePanel(panelType.AdministratorCreation);
                } else {
                    alert(this.DatabaseConnectionMessage);
                }                               
            },
            error => this.errorMessage = <any>error);
    }

 

Programmatically Create An Administrator

image

If an Administrator does not exist, the user is required to enter the information to create one, and click the Create Account button that triggers the following code:

 

   createAdministrator() {
        this.errorMessage = "";
        let email = this.CreateAdminEmail;
        let password = this.CreateAdminPassword;
        if (this.validatePassword(password) &&
            this.validateEmail(email)) {            
            let Authentication: IAuthentication = {
                Email: email,
                Password: password
            };
            // Call the service
            this._installWizardService.createAdmin(Authentication).subscribe(
                response => {
                    // Call the method to see who 
                    // the server-side OData code 
                    // thinks is logged in
                    this.getCurrentUser();
                    // Move to the next step
                    this.setActvePanel(panelType.AdministratorLogin)
                },
                error => this.errorMessage = <any>error);
        }
        else {
            alert('password [ ' + password + ' ] is not strong enough');
        }
    }

 

This calls the following Angular service method:

 

    createAdmin(Authentication: IAuthentication): Observable<string> {
        var Url = 'api/Angular2Admin/CreateAdminLogin';
        // This is a Post so we have to pass Headers
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        // Make the Angular 2 Post
        return this._http.post(Url, JSON.stringify(Authentication), options)
            .map((response: Response) => <string>response.status.toString())
            .do(data => console.log('loginUser: ' + JSON.stringify(data)))
            .catch(this.handleError);
    }

 

This calls the a server side method that calls the following method to actually create the administrator account:

 

        private ApplicationUser CreateAdmin(string strEmail, string strPassword)
        {
            const string AdministratorRoleName = "Administrator";
            // See if User exists
            ApplicationUser objUser = UserManager.FindByName(strEmail);
            if (objUser == null)
            {
                // Create Administrator Role
                var roleManager =
                    new RoleManager<IdentityRole>(
                        new RoleStore<IdentityRole>(new ApplicationDbContext()));
                if (!roleManager.RoleExists(AdministratorRoleName))
                {
                    roleManager.Create(new IdentityRole(AdministratorRoleName));
                }
                // Create Admin user
                var objNewUser = new ApplicationUser {
                    UserName = strEmail, Email = strEmail };
                var UserCreateResult = UserManager.Create(objNewUser, strPassword);
                // Make user an Admin
                UserManager.AddToRole(objNewUser.Id, AdministratorRoleName);
            }
            // Return User
            objUser = UserManager.FindByName(strEmail);
            return objUser;
        }

 

 

Log Into The Application Using Angular

image

The user is required to log in to perform any wizard step past the initial set-up.

image

An explanation of the code that logs a user into an Asp.net application from Angular is covered in the following article: Angular 2+ Logging Into An ASP.NET 4.5 Application

The Application

image

When the Install wizard is complete, the application loads.

The application that allows a user to enter and manage a list of Products is covered in the following article:

Tutorial: Creating An Angular 2 CRUD Application Using MVC 5 and OData 4.

 

Notes

  • The wizard will show if a database table called version has not been created and a record entered that is set to at least version 1.0.0, or the table is set up but the version indicated is less than the target database version indicated in the OData method.
  • This wizard does not support SQL Server express in File mode only in .
  • This wizard only supports Microsoft SQL Server 2005 and above

 

Links

Github repository

Download

The project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

You must have Visual Studio 2015 Update 3 (or higher) and TypeScript 2.0 (or higher) installed to run the code.


Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation