2016年10月18日 星期二

[ASP.NET Core X Angular](1) – Hello world!

 Angular     MVC core    ASP.NET Core




Introduction


Angular2 2.1.0 is released on October. It’s a good time to start learning it!
We can use Angualr CLI to quickly build the architecture for ng2.
However, in this article I will combine the frameworks and benefits of ASP.NET core MVC and web api with Angular 2, to make a SPA (Single Page Application) sample.

Visual Studio templates 
For those who want to quickly create the development template, there are some ASP.NET core +angular 2 templates released.






Environment

Visual Studio 2015 Update 3
NPM: 3.10.3                                    
Microsoft.AspNetCore.Mvc 1.0.0
angular 2: 2.1.0


Create MVC website and install packages


Create MVC

Choose ASP.NET Core Web Application (.NET Core) project template and using the EMPTY template.









Install frameworks/packages

Open project.json, add the following packages in “dependencies”.

"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.Mvc": "1.0.0",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "es6-shim.TypeScript.DefinitelyTyped": "0.8.1"
  },






Set MVC rounting rule

We are going to set the default and AREA routing rules for MVC.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // Add static files to the request pipeline.
            app.UseStaticFiles();
           
            app.UseMvc(routes => {

                routes.MapRoute(
                   name: "areaRoute",
                   template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

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

View and Controller

Now we can add the controller, view and master page (_Layout.cshtml) in the project.
Then run it!




The MVC website is ready, we will install packages for angular2, bootstrap later.




Bower : install bootstrap and jquery(optional)


Install

Add bower.json to the root of our project, then add the following packages within it.

 

Save bower.json and wait for the packages are installed under the path $/wwwroot/lib/.












Update _Layout.cshtml

Put bootstrap js and css into _Layout.cshtml’s <header> in order to style our website.

<head>
    <script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
    <link href="~/lib/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
</head>







npm and gulp


Install packages

We will need the packages for developing the SPA:
9.  rxjs 
12. Zone.js 
13. es6-shim 


Typescript
2.  typings

And the following packages for managing the js and packages.
1.  rimraf
2.  gulp

Optional js library


Here is my package.json snapshot for your reference.

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "Dependencies": {
    "systemjs": "0.19.39",
    "es6-shim": "^0.33.3",
    "rxjs": "5.0.0-rc.1",
    "sweetalert2": "5.2.1"
  },
  "devDependencies": {
    "systemjs": "0.19.39",
    "es6-shim": "^0.33.3",
    "rxjs": "5.0.0-rc.1",
    "gulp": "3.8.11",
    "gulp-concat": "2.5.2",
    "gulp-cssmin": "0.1.7",
    "gulp-uglify": "1.2.0",
    "rimraf": "2.2.8",
    "sweetalert2": "5.2.1",
    "typescript": "2.0.3",
    "typings": "1.4.0"
  },
  "dependencies": {
    "@angular/common": "^2.1.0",
    "@angular/compiler": "^2.1.0",
    "@angular/core": "^2.1.0",
    "@angular/forms": "^2.1.0",
    "@angular/http": "^2.1.0",
    "@angular/platform-browser": "^2.1.0",
    "@angular/platform-browser-dynamic": "^2.1.0",
    "@angular/router": "3.1.0",
    "reflect-metadata": "^0.1.8",
    "zone.js": "^0.6.25"
  }
}


PS. You can see more details about systemjs, es6-shim and rxjs in their Github.


The packages will be installed to $/node_modules
In the next step, we will use gulp to move the packages from $/node_modules to $/wwwroot/lib-npm


Gulp: tasks

Add a gulp config (gulpfile.js) and write the copy tasks.

"use strict";
var gulp = require('gulp');
var root_path = {
    webroot: "./wwwroot/"
}

//library source
root_path.nmSrc = "./node_modules/";
//library destination
root_path.package_lib = root_path.webroot + "lib-npm/"

//rxjs
gulp.task("copy-rxjs", function () {
    return gulp.src(root_path.nmSrc + '/rxjs/**/*.js', {
        base: root_path.nmSrc + '/rxjs/'
    }).pipe(gulp.dest(root_path.package_lib + '/rxjs/'));
});

//reflect-metadata
gulp.task("copy-reflect-metadata", function () {
    return gulp.src(root_path.nmSrc + '/reflect-metadata/*.js', {
        base: root_path.nmSrc + '/reflect-metadata/'
    }).pipe(gulp.dest(root_path.package_lib + '/reflect-metadata/'));
});

//zone.js
gulp.task("copy-zonejs", function () {
    return gulp.src(root_path.nmSrc + '/zone.js/dist/**/*.js', {
        base: root_path.nmSrc + '/zone.js/dist/'
    }).pipe(gulp.dest(root_path.package_lib + '/zone.js/'));
});


//angular2
gulp.task('copy-ng2-common', function () {
    return gulp.src(root_path.nmSrc + "/@angular/common/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/common/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/common/'));
});
gulp.task('copy-ng2-compiler', function () {
    return gulp.src(root_path.nmSrc + "/@angular/compiler/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/compiler/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/compiler/'));
});
gulp.task('copy-ng2-core', function () {
    return gulp.src(root_path.nmSrc + "/@angular/core/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/core/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/core/'));
});
gulp.task('copy-ng2-forms', function () {
    return gulp.src(root_path.nmSrc + "/@angular/forms/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/forms/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/forms/'));
});
gulp.task('copy-ng2-http', function () {
    return gulp.src(root_path.nmSrc + "/@angular/http/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/http/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/http/'));
});
gulp.task('copy-ng2-router', function () {
    return gulp.src(root_path.nmSrc + "/@angular/router/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/router/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/router/'));
});
gulp.task('copy-ng2-platform-browser', function () {
    return gulp.src(root_path.nmSrc + "/@angular/platform-browser/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/platform-browser/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/platform-browser/'));
});
gulp.task('copy-ng2-platform-browser-dynamic', function () {
    return gulp.src(root_path.nmSrc + "/@angular/platform-browser-dynamic/bundles/**/*.js", {
        base: root_path.nmSrc + '/@angular/platform-browser-dynamic/bundles/'
    }).pipe(gulp.dest(root_path.package_lib + '/angular2/platform-browser-dynamic/'));
});

//systemjs
gulp.task('copy-systemjs', function () {
    return gulp.src(root_path.nmSrc + "/systemjs/dist/**/*.*", {
        base: root_path.nmSrc + '/systemjs/dist/'
    }).pipe(gulp.dest(root_path.package_lib + '/systemjs'));
});
//ES6
gulp.task('copy-es6-shim', function () {
    return gulp.src(root_path.nmSrc + "/es6-shim/es6-sh*", {
        base: root_path.nmSrc + '/es6-shim/'
    }).pipe(gulp.dest(root_path.package_lib + '/es6-shim'));
});
//sweetalert2
gulp.task('copy-sweetalert2', function () {
    return gulp.src(root_path.nmSrc + "/sweetalert2/dist/sweetalert2*", {
        base: root_path.nmSrc + '/sweetalert2/dist/'
    }).pipe(gulp.dest(root_path.package_lib + '/sweetalert2/'));
});

gulp.task("copy-all", [
    "copy-rxjs",
    "copy-reflect-metadata",
    "copy-zonejs",
    "copy-ng2-common",
    "copy-ng2-compiler",
    "copy-ng2-core",
    "copy-ng2-forms",
    "copy-ng2-http",
    "copy-ng2-router",
    "copy-ng2-platform-browser",
    "copy-ng2-platform-browser-dynamic",
    "copy-systemjs",
    "copy-es6-shim",
    "copy-sweetalert2"])



Run the following command (or use the task runner in visual studio).
$ gulp copy-all




I created an extra folder named “typings” to store the 3rd typing definition files.
In this sample, we will need es6-shim.d.ts and sweetalert.d.ts 



Using the packages and modules


Add tsconfig.json




{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    //add this to compile app component
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "system",
    "moduleResolution": "node"
  },
  "exclude": [ "node_modules", "wwwroot/lib" ]
}




Load packages

Okay, now we can add the necessary references of the packages on the _Layout.cshtml
Notice that we are going to use anuglar’s router for building SPA.
So we have to set the BASE URL: <base href="/">

<head>
    <base href="/">
    <script src="~/lib-npm/reflect-metadata/Reflect.js"></script>
    <script src="~/lib-npm/zone.js/zone.js"></script>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib-npm/es6-shim/es6-shim.js"></script>
    <script src="~/lib-npm/systemjs/system.src.js"></script>
    <script src="~/lib-npm/sweetalert2/sweetalert2.min.js"></script>
    <link href="~/lib-npm/sweetalert2/sweetalert2.min.css" rel="stylesheet" />
    <script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
    <link href="~/lib/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
</head>


Load dynamic modules

We are going to use Systemjs to load the dynamic modules: @angular and rxjs.
Create systemjs.config.js in $/wwwroot/app/ or other path.

systemjs.config.js

System.config({
    transpiler: 'typescript',
    typescriptOptions: { emitDecoratorMetadata: true },
    map: {
        'rxjs': 'lib-npm/rxjs',
        '@angular': 'lib-npm/angular2'
    },
    packages: {
        'rxjs': { main: 'Rx.js' },
        '@angular/router': { main: 'router.umd.min.js'},
        '@angular/core': { main: 'core.umd.min.js' },
        '@angular/common': { main: 'common.umd.min.js' },
        '@angular/compiler': { main: 'compiler.umd.min.js' },
        '@angular/forms': { main: 'forms.umd.js' },
        '@angular/platform-browser': { main: 'platform-browser.umd.min.js' },
        '@angular/platform-browser-dynamic': { main: 'platform-browser-dynamic.umd.min.js' }
    }
});


Next, we put this js to the _Layout.cshtml.

<head>
   <!-- skip ... -->
    <script src="~/app/systemjs.config.js"></script>
</head>


PS. If you got any system.js error in the following process, it may be something wrong within this file!



▌Angular2


We will create a quick ng2 page sample in this step.
If you wanna to know more about the basics of ng2, you can start with the official tutorial or my previous tutorial with vscode.


Target the browser platform, and create ng2 module and component

We need to create the 3 files to fire an ng2 application.
1.  app.module.ts : imports necessary modules and declarations.
2.  app.component.ts : our directive.
3.  main.ts  : bootstrapping and target the browser platform.


wwwroot/app/app.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'core-app',
    template: '<h3>Hello world!</h3>'
})
export class AppComponent implements OnInit {
    ngOnInit() {
    }


wwwroot/app/app.module.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 { }




wwwroot/app/main.ts

import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app.module';
import {enableProdMode} from '@angular/core';

//enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);





Then update $/Views/Home/Index.cshtml and add the directive to it.

Views/Home/Index.cshtml

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>
<core-app>
    <div>
        <p><img src="~/images/gif/ajax-loader.gif" /> Please wait ...</p>
    </div>
</core-app>

@section Scripts {
   <script>
        System.config({
            map: {
                app: 'app'
            },
            packages: {
                app: {main: 'main.js',defaultExtension: 'js'}
            },
        });
        System.import('app/main').then(null, console.error.bind(console));
    </script>
}

Note : Use systemjs: System.import to add the compiled typescript to the HTML.


Result







What’s next?

In the next tutorial, we will create a SPA for create/update/delete/see detail.



Github





Reference

rxjs


沒有留言:

張貼留言