Feb
5
Written by:
Michael Washington
2/5/2017 2:45 PM
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
The first step is to create a database using SQL Server.
Next, download the project from the downloads page on this site, and unzip the file.
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.
In Visual Studio, select Debug, then Start Debugging, to run the project.
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.
The next screen asks you to create an administrator account.
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.
At this step, any additional install scripts will run.
When they are complete, the Continue button will show.
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
This sample project makes extensive use of the free open source PrimeNG Angular 2 components.
How To Set-Up An Upgrade
The project allows you to trigger the Install Wizard to upgrade the database by simply adding a new .sql file to the !SQLScripts folder…
… 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
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
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
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
The user is required to log in to perform any wizard step past the initial set-up.
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
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.