(#02) ASP.Net Core + Angular 2 … adding Angular 2

Follow the Angular 2 quick start tutorials for guidance on the basics of Angular 2. We’ll be following the typescript version (nothing like extending yourself), we’ll get strongly typed code, with a structure not dissimilar to C#, and add ‘transpiling’ to ensure the typescript code gets copied and compiled into JavaScript to run in the browser.

Note: There’s plenty of explanation on the Angular 2 quick start tutorial site explaining the functions of Angular 2, typescript and how the Angular 2 boot-loader/bootstrap works, I’ll only be including details where these are altered through using ASP.Net Core or how we’ll modify things.

Add a new folder ‘app’ to the ASP.Net Core wwwroot folder, add new files to the app folder called ‘app.component.ts’, ‘app.module.ts’ and ‘main.ts’.

Copy the quick start sample contents into these, then in the root of the wwwroot directory add ‘index.html’ (just for initial testing, we’ll replace this flat html file with an ASP.Net Core .cshtml file) as well as ‘system.config.js’. Again copy into these new files the content from the corresponding files shown in quick start sample.

To get the dependencies / libraries ready to use, create a .json file called ‘package.json’ in the root directory of the project, this will contain a list of the node package manager (NPM) modules required.

Add the following content into package.json:

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
    "@angular/common": "2.0.0",
    "@angular/compiler": "2.0.0",
    "@angular/core": "2.0.0",
    "@angular/forms": "2.0.0",
    "@angular/http": "2.0.0",
    "@angular/platform-browser": "2.0.0",
    "@angular/platform-browser-dynamic": "2.0.0",
    "@angular/router": "3.0.0",
    "@angular/upgrade": "2.0.0",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.12",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.23"
  },
  "dependencies": {
  }
}

Save the file, you should find these packages are automatically  restored by Visual Studio 2015. If you are using Visual Studio Code, or interested in what is going on, you can restore the files manually. Open a command prompt up (windows, type cmd then right click it, and select ‘run as administrator’). Navigate to the physical folder containing the root directory of the project, then type:

npm install

For this you will need a reasonable recent version of Node.js installed, go to https://nodejs.org/ if you need, install node and ensure the path is set up (if changed, you will need to re-load the cmd window).

Next we need to add a couple of new asp.net core packages to the dependencies section of project.json:

    "Microsoft.AspNetCore.Mvc.WebApiCompatShim": "1.0.1",
    "Microsoft.AspNetCore.SpaServices": "1.0.0-beta-000014"

Save project.json and again Visual Studio 2015 should restore these new packages, though you can also restore them manualy using the same cmd prompt, as above, but typing

dotnet restore

To setup typescript add the file ‘tsconfig.json’ to the root directory, containing this:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

and also add the file typings.json’ to the root directory, containing this:

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160725163759"
  }
}

Lastly edit the startup.cs file to ensure the web server is configured to serve up static files from the node_modules folder, as well as those making up the angular app itself.

Add these to the using statementsto the top of setup.cs:

using Microsoft.Extensions.FileProviders;
using System.IO;

and change the bottom section of setup.cs inside the from this:

             app.UseStaticFiles();
             app.UseMvc(routes =>
             {
                routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
             });

to this:

            app.UseStaticFiles();
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")),
                RequestPath = "/node_modules"
            });

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
                routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
                routes.MapWebApiRoute("defaultApi", "api/{controller}/{id?}");
                // routes.MapRoute("fallback", "{*anything}", new { controller = "Home", action = "Index" });
                routes.MapSpaFallbackRoute("spa-fallback", new { controller = "home", action = "index" });
            });
        }
    }

hit ctrl-F5 browse to http://localhost:7010/index.html and you should see this:

my-first-angular-2-app

If this doesn’t work, either grab a copy of the repo, here: Github source of this step  or check the index.html file contains this:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2 QuickStart</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">
 
    <!-- Polyfill(s) for older browsers -->
    < script src="node_modules/core-js/client/shim.min.js"></script>
 
    < script src="node_modules/zone.js/dist/zone.js"></script>
    < script src="node_modules/reflect-metadata/Reflect.js"></script>
    < script src="node_modules/systemjs/dist/system.src.js"></script>
 
    < script src="systemjs.config.js"></script>
    < script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>
 
  <body>
    <my-app>Loading...</my-app>
  </body>
</html>

The ‘app.component.ts’ file should be:

import { Component } from '@angular/core';
 
@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

the ‘app.module.ts’ file should contain:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
 
import { AppComponent }  from './app.component';
 
@NgModule({
  imports: [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

and ‘main.ts’ should be:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
 
import { AppModule } from './app.module';
 
platformBrowserDynamic().bootstrapModule(AppModule);

if all else fails, check ‘system.config.js’ against this:

/**
 * System configuration for Angular 2 samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': 'node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: 'app',
 
      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
 
      // other libraries
      'rxjs':                       'npm:rxjs',
      'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular2-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);

If all else fails, again grab the repo directly from Github.

The next  part will describe how to replace the embedded HTML or static HTML templates commonly used in Angular 2 with CSHTML generated on the server. This will allow us immediately to use Razor markup to run server side code, and later we’ll also set up the project to make use of tag helpers to automatically generate code.

 

 

 

 

 

 

 

Advertisements