Building the angular.io quickstart with ASP.NET Core

When you start to explore angular 2, probably the best place to start is taking the quick start on angular.io.

In this post I will show you how you can setup the project to use Visual Studio 2015 and ASP.NET Core, since the quick start from angular.io doesn't work as described with ASP.NET Core. Some of the changes are different conventions (putting the libraries in the wwwroot/lib folder for example), and some changes are because we will be using gulp...

 

I will give you step by step instructions on how to setup the project, explanations about why can be found on angular.io.

 

Start by creating a new ASP.NET Core project in Visual Studio:

image

Click OK. In the next screen pick the Empty template.

Open project.json and add a dependency to the StaticFiles package:

"dependencies": {
  "Microsoft.NETCore.App": {
    "version": "1.0.0",
    "type": "platform"
  },
  "Microsoft.AspNetCore.Diagnostics": "1.0.0",
 
  "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
  "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
  "Microsoft.Extensions.Logging.Console": "1.0.0",
  "Microsoft.AspNetCore.StaticFiles": "1.0.0"
},

Save your changes so NuGet will install the package.

Open Startup.cs and add the StaticFiles middleware:

app.UseDefaultFiles(new DefaultFilesOptions
{
  DefaultFileNames = new string[] { "index.html" }
});
app.UseStaticFiles();

Now add a new JSON file to the project (next to project.json) called package.json:

{
  "name": "angular2-quickstart",
  "version": "1.0.0",
  "scripts": {
    "postinstall": "typings install",
    "typings": "typings"
  },
  "license": "ISC",
  "dependencies": {
    "@angular/common": "2.0.0-rc.5",
    "@angular/compiler": "2.0.0-rc.5",
    "@angular/core": "2.0.0-rc.5",
    "@angular/forms": "0.3.0",
    "@angular/http": "2.0.0-rc.5",
    "@angular/platform-browser": "2.0.0-rc.5",
    "@angular/platform-browser-dynamic": "2.0.0-rc.5",
    "@angular/router": "3.0.0-rc.1",
    "@angular/router-deprecated": "2.0.0-rc.2",
    "@angular/upgrade": "2.0.0-rc.5",
    "angular2-in-memory-web-api": "0.0.15",
    "bootstrap": "^3.3.6",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.12"
  },
  "devDependencies": {
    "typescript": "^1.8.10",
    "gulp": "^3.9.1",
    "path": "^0.12.7",
    "gulp-clean": "^0.3.2",
    "gulp-concat": "^2.6.0",
    "gulp-typescript": "^2.13.6",
    "typings": "^1.3.1",
    "gulp-tsc": "^1.2.0"
  }
}
Save this file to make visual studio do a npm install.
 
image
 

Add another JSON file called typings.json

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160602141332",
    "jasmine": "registry:dt/jasmine#2.2.0+20160621224255",
    "node": "registry:dt/node#6.0.0+20160807145350"
  }
}
Right-click the Dependencies folder and choose Restore packages. This will install the typings.
 
Now add a gulp configuration file (gulpfile.js):
var ts = require('gulp-typescript');
var gulp = require('gulp');
var clean = require('gulp-clean');
var destPath = './wwwroot/lib/';
// Delete the dist directory
gulp.task('clean', function () {
  return gulp.src(destPath)
      .pipe(clean());
});
gulp.task("scriptsNStyles", () => {
  gulp.src([
          'core-js/client/**',
          'systemjs/dist/system.src.js',
          'reflect-metadata/**',
          'rxjs/**',
          'zone.js/dist/**',
          '@angular/**',
          'jquery/dist/jquery.*js',
          'bootstrap/dist/js/bootstrap.*js',
  ], {
    cwd: "node_modules/**"
  })
      .pipe(gulp.dest(destPath));
});
var tsProject = ts.createProject('app/tsconfig.json');
gulp.task('ts', function (done) {
  //var tsResult = tsProject.src()
  var tsResult = gulp.src([
          "app/*.ts"
  ])
      .pipe(ts(tsProject), undefined, ts.reporter.fullReporter());
  return tsResult.js.pipe(gulp.dest('./wwwroot/app'));
});
gulp.task('watch', ['watch.ts']);
gulp.task('watch.ts', ['ts'], function () {
  return gulp.watch('app/*.ts', ['ts']);
});
gulp.task('default', ['scriptsNStyles', 'watch']);

Open Task Runner Explorer and run the default task (you might need to refresh it first).

This will setup a watch that will look for typescript (.ts) files in the app folder of your project, compile them and then copy them into wwwroot/app.

Time to add this app folder, so right-click your project, choose Add New Folder, and name it app:

In it add the TypeScript Configuration file (tsconfig.json):

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "commonjs",
    "noEmitOnError": true,
    "noImplicitAny": false,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    "moduleResolution": "node"
  },
  "exclude": [
    "node_modules",
    "typings/index",
    "typings/index.d.ts"
  ]
}

NOTE: If you don't like the compiler output to end up in your source folder you can actually use the outDir to put them somewhere else, for example:

    "outDir": "../wwwroot/app/"

Now add a new TypeScript file called app.component.ts:

NOTE: If you get compile errors, right-click the Node Dependencies folder and restore them.

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }
Add another TypeScript file called app.module.ts:
///<reference path="./../typings/globals/core-js/index.d.ts"/>
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 { }
Add another one called main.ts:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
Almost there...
 
Open wwwroot and look for (or create) the js folder.
Add a new javascript file in this folder called systemjs.config.js:
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function (global) {
  // map tells the System loader where to look for things
  var map = {
    'app': 'app', // 'dist',
    '@angular': 'lib/@angular',
    'angular2-in-memory-web-api': 'lib/angular2-in-memory-web-api',
    'rxjs': 'lib/rxjs'
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    'app': { main: 'main.js', defaultExtension: 'js' },
    'rxjs': { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
  };
  var ngPackageNames = [
    'common',
    'compiler',
    'core',
    'forms',
    'http',
    'platform-browser',
    'platform-browser-dynamic',
    'router',
    'router-deprecated',
    'upgrade',
  ];
  // Individual files (~300 requests):
  function packIndex(pkgName) {
    packages['@angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' };
  }
  // Bundled (~40 requests):
  function packUmd(pkgName) {
    packages['@angular/' + pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
  }
  // Most environments should use UMD; some (Karma) need the individual index files
  var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
  // Add package entries for angular packages
  ngPackageNames.forEach(setPackageConfig);
  var config = {
    map: map,
    packages: packages
  };
  System.config(config);
})(this);
This file differs from the one on angular.io in where it will look for things (lib instead of node_modules)...
Now add a html file under the wwwroot folder called index.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="css/styles.css">
    <!-- 1. Load libraries -->
    <!-- Polyfill(s) for older browsers -->
    <script src="lib/core-js/client/shim.min.js"></script>
    <script src="lib/zone.js/dist/zone.js"></script>
    <script src="lib/reflect-metadata/Reflect.js"></script>
    <script src="lib/systemjs/dist/system.src.js"></script>
    <!-- 2. Configure SystemJS -->
    <script src="js/systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
</head>
<!-- 3. Display the application -->
<body>
    <my-app>Loading...</my-app>
</body>
</html>
And don't forget to add a .css style (web developers always have style right?!).
Create a css folder under wwwroot, and add a css file called styles.css:
h1 {
  color: #369;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 250%;
}
body {
  margin: 2em;
}
 

Hit F5 to run your angular 2 web site. If all goes well you should see:

image

And if you want to learn a lot more about Angular 2, we have an excellent training on it!