65.9K
CodeProject 正在变化。 阅读更多。
Home

Angular 2 结合 ASP.NET Core Web API – 构建一个简单的笔记本应用 – 第一部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (5投票s)

2016年11月24日

CPOL

9分钟阅读

viewsIcon

39579

downloadIcon

870

逐步构建一个运行在 IIS 和 ASP.NET Core 上的 Angular 2 应用。该项目还包含实时示例。这是构建 Angular 2 笔记本 WebApp 的第一部分。

本文介绍了创建 Angular2 应用的分步方法,该应用将消耗 ASP.NET Core REST WebAPI。它延续了之前的文章 使用 MongoDB 结合 ASP.NET Core WebAPI,并对 Angular 2 框架进行了初步介绍。

这是第一部分,本系列的范围是逐步展示如何构建

一个可以轻松存储想法的 Web 应用,添加文本笔记,无论是从桌面还是移动设备,具有以下特点:运行速度快,即时保存你写的内容,并且具有相当的可靠性和安全性。

涵盖的主题

  • Angular 2 模块
  • Angular 2 组件
  • Angular 2 依赖注入
  • Angular 2 生命周期
  • Angular 2 服务和 Observable
  • 创建一个连接到 ASP.NET Core WebApi 项目的 Angular 2 应用

为什么选择 Angular 2?

Angular2 是一个框架,开箱即用地提供了大量功能。它拥有路由、WebApi 调用、依赖管理等库。Angular2 还采用了 TypeScriptTypeScript 是 JavaScript 的超集。它与 Visual Studio 集成得非常好,在您输入代码时提供建议,并在您输入代码时发现错误。

新版本的 Angular 提供了更一致、更简洁的开发体验。 它也更快,开箱即用地提供服务器端渲染,跨平台,支持旧版浏览器等。

使用 Plunker 进行实时代码演示

即使 Angular 2 框架有其优势,但与 ASP.NET Core 结合的解决方案一开始似乎很困难。为了让事情更轻松,每个部分都附带一个实时的 Angular 2 示例。这些示例从简单的“hello world”类型演变而来,到从 WebAPI 读取数据。您可以在阅读文章时查看它们,或者从此摘要中快速访问它们

轻松访问代码

博客从一个预配置的 ASP.NET Core 解决方案开始,最终到一个连接到 WebAPI 的应用程序。您可以使用下面的链接访问这两个项目

安装说明

以下是本地安装所需的所有内容

开始使用 Angular 2 和 TypeScript

开始学习 Angular 2 和 TypeScript 的最佳方法是克隆一个应用程序启动器,这是一个极简的 Angular 2 应用,它具有 Angular 2、TypeScript 和模块加载器的完整设置。

首先,一旦安装了上面介绍的所有项目,我们需要确保 node 和 npm 版本正确。Angular 2 使用 node v4.x.x 或更高版本以及 npm 3.x.x 或更高版本运行。

为了能够检查版本,我打开了一个命令提示符并运行了

c:\windows\system32>npm --version
3.10.8
c:\windows\system32>node --version
v6.9.1

我的本地设置满足最低要求。如果您在 npm 版本方面遇到问题,请参阅 下一篇文章

一旦这些版本正确,我们就可以继续从 Github 克隆 初始项目(或者更简单地 下载它)。

在打开初始解决方案之前的最后一件事是安装 Gulp。在命令提示符中,在项目文件夹中运行此命令

npm install gulp --save-dev

此命令将本地安装 Gulp。入门项目具有所有现成的配置,以及一个完全配置的 Gulp 文件。

在 Visual Studio 中打开解决方案。根据互联网连接的速度,本地下载所有必需的包可能需要一段时间。一旦完成,可能在几分钟后,构建解决方案并运行它。

以下是为使我们能够运行 Angular 2 和 ASP.NET Core MVC 而添加或更新的文件

// Angular 2 source code details
- app folder            # Angular2 source folder
-  /css & /js           # Folders for CSS & additional Java script files
- note.app.module.ts    # The Angular module & sample component

// ASP.NET Core - Updated files 
- Controllers/HomeController.cs     # Default ASP.NET MVC Controller, at the beginning with no change
- Views/Home/Index.cshtml           # Default ASP.NET MVC View, loads the Angular2 module
- Startup.cs                        # Make the static files servable 

// TypeScript configuration
- gulpfile.js           # Gulp configuration file for automating the deployment flow
- hosting.js            # Configuration file added to run the application on a specific port
- package.json          # NPM could identify the project as well as handle the project's dependencies.
- systemjs.config.js    # Allows to configure SystemJS to load modules compiled using the TypeScript compiler.
- tsconfig.json         # TypeScript compiler configuration
- typings.json          # TypesScript declaration file

模块、引导、组件

  • 在 Angular 1 中,我们使用 ng-app 指令将 Angular 指向应用程序的起始点。在 Angular 2 中,我们使用引导程序。Angular 2 是平台无关的。我们可以在浏览器中运行它,但也可以在 Web Worker、服务器上运行,并可能使用不同的引导程序在移动设备上原生运行。
    platformBrowserDynamic().bootstrapModule(AppModule);
  • Angular 2 模块和新的 NgModule 装饰器允许我们在一个地方声明应用程序的所有依赖项和组件,而无需像以前那样按组件进行声明。在这里,我们指示 App 组件应该首先加载。
    @NgModule({
        imports: [BrowserModule],
        declarations: [App],
        bootstrap: [App]
    })
    
    export class AppModule { }
  • 组件是可重用的 UI 部分,由自定义 HTML 元素显示。它是自包含的,至少由一段称为模板的 HTML 代码、封装该模板可用数据和交互的类,以及也称为选择器的上述 HTML 元素组成。
    @Component({
        selector: 'notes-app',
        template: `<div>
                  <h2>NotebookApp with {{name}}</h2>
                   </div>`
    })
    
    export class App {
        name: string;
        constructor() {
            this.name = 'Angular 2';
        }
    }
  • 要显示,我们在 ASP.NET Core 视图中包含新的 HTML 标签
    <notes-app></notes-app>
    
    <script>
        System.import('dist/note.app.module')
              .catch(function (err) { console.error(err); });
    </script>

您可以通过运行解决方案来查看结果,或者使用 Plunker 中的第一个示例:预览 A – Angular 2 – 入门应用

添加第一个组件:列出笔记

我们要做的第一件事不需要服务,现在还不需要。我们将创建第一个组件来显示笔记列表,并开始模拟这些数据。

最好先定义我们问题空间的域模型,在本例中是 NoteItem。我们将利用 TypeScript 接口并在 noteModel.ts 文件中创建一个 NoteItem。为简单起见,我们将暂时将所有字段(包括 date)都设为 string。组件名称为:NotesComponent

export interface NoteItem {
    Id: string,
    Body: string,
    UpdatedOn: string,
    CreatedOn: string,
    UserId: number
}

要遍历笔记列表,我们将使用 *ngFor,这是一个重复器指令。代码片段将显示如下

<ul>
    <li *ngFor="let note of noteItems">
      {{note.Body}}
    </li>
  </ul>

现在,我们更新 NotesComponent 组件并显示数据

import { Component } from '@angular/core'
import { NoteItem } from './note.model'

@Component({
  selector: 'notes-app',
  template: `
  <ul>
    <li *ngFor="let note of noteItems">
      {{note.Body}}
    </li>
  </ul>
  `
})
export class NotesComponent {
  noteItems: NoteItem[] = [
    {Id:'1', Body: 'First note', UpdatedOn: '2016-11-21 10:20:23', 
     CreatedOn: '2016-11-21 10:20:23', UserId: 1},
    {Id:'2', Body: 'Second note with more details', UpdatedOn: '2016-11-21 10:20:23', 
     CreatedOn: '2016-11-21 10:20:23', UserId: 1},
    {Id:'3', Body: 'Third note, and the last sample', UpdatedOn: '2016-11-21 10:20:23', 
     CreatedOn: '2016-11-21 10:20:23', UserId: 1},
  ];
}

您可以在 Plunker 中看到相同的 Angular 2 代码:预览 B – Angular 2 – 第一个组件

依赖注入和通用设置

为了更容易地呈现 Angular 2 中的依赖注入 (DI),让我们使用一个通用的设置类,该类需要被其他组件访问。它的构建方式可以进一步扩展(例如:从配置文件读取),但更简单的模型有助于我们更好地呈现 Angular 2 中的依赖注入

让我们从一个简单的类开始

export class Configuration {
    public ApiServer: string = "https://:6001/";
    public ApiUrl: string = "api/notes";
    public ServerWithApiUrl: string = this.ApiServer + this.ApiUrl;
}

为了通过 DI 使其可供其他组件访问,我们进行两项更改

  • 使该类可注入
    import { Injectable } from '@angular/core';
    
    @Injectable()
    export class Configuration {
        public ApiServer: string = "https://:6001/";
        public ApiUrl: string = "api/notes";
        public ServerWithApiUrl: string = this.ApiServer + this.ApiUrl;
    }
  • 然后,在模块配置中将其作为提供者可用
    @NgModule({
        imports: [BrowserModule],
        declarations: [NotesComponent],
        providers: [Configuration],
        bootstrap: [NotesComponent]
    }

    这些更新允许我们通过构造函数将 Settings 注入到我们的组件中。

    export class NotesComponent {
        constructor(private _dataService: NoteService) {

在 Plunker 中实时查看此内容:预览 C – Angular 2 – 可注入

使用 Angular 2 组件生命周期

当组件创建时,会调用其构造函数,然后初始化我们的组件。如果我们依赖于其他组件的属性或数据,那么我们就需要等待其他组件先初始化。为了能够做到这一点,我们使用 ngOnInit 生命周期。这将允许我们在初始化此服务时调用 WebApi。

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

...

export class NotesComponent implements OnInit {
    ngOnInit() {
       // access the WebAPI service    
    }
}

创建 Angular 2 服务

Angular 2 服务只是一个封装功能的 ES6 类。它被应用程序的其余部分使用,并被称为服务。

在下面的示例中,我们创建了一个使用原生 Angular 2 http 服务的类,它允许我们接收 json 详细信息。该类还被标记为可注入,以便更容易访问和使用。

import { Injectable } from "@angular/core";
import { Http } from "@angular/http";
import "rxjs/add/operator/map";
import { Observable } from "rxjs/Observable";
import { NoteItem } from "../../models/note/noteModel";
import { Configuration } from "../../app.constants";

@Injectable()
export class NoteService {
    constructor(private _http: Http, private _configuration: Configuration) {
    }

    public getAll = (): Observable<NoteItem[]> => {
        return this._http.get(this._configuration.ServerWithApiUrl) 
            .map(data => data.json());
    };

我们在上面的代码片段中使用了更多术语,这里有一些细节

  • Angular 2 http 客户端服务提供了进行 HTTP 请求的支持,并附带了与 HTTP 动词(如 getpostput 等)对应的所有方法。
  • Observable 是 Angular 2 中使用的异步模式。Observable 的概念来源于观察者设计模式,它是一个对象,当发生某事时会通知感兴趣的观察者集合。在 RxJs 中,它已被泛化为管理数据或事件序列,使其能够与其他 observable 组合,并提供大量称为操作符的实用函数。
  • map 将序列中的项转换为我们应用程序的域模型 – 在本例中是 noteItems

要使用此模式,我们应该订阅 observable。我们通过 .subscribeObservable<noteitem[]> 来做到这一点。一旦异步接收到详细信息,我们就填充局部变量 myItems

export class NotesComponent implements OnInit {
    public myItems: NoteItem[];

    constructor(private _dataService: NoteService) {
    }

    ngOnInit() {
        this._dataService
            .getAll()
            .subscribe((data: NoteItem[]) => this.myItems = data,
            () => console.log("getAllItems() complete from init"));
    }

仅进行检索(GET),我们可以通过读取 JSON 文件来模拟外部服务。在 Plunker 中查看 Angular 2 服务的概念:预览 D – Angular 2 服务连接到 REST WebAPI

使用 Observable 进行错误处理

第一级错误处理应发生在服务级别。在此较低级别可以处理与 HTTP 请求相关的问题。在此简单应用程序中,我们将仅记录错误,并将其转换为应用程序级别的错误

export class NotesComponent implements OnInit {
    public myItems: NoteItem[];

    constructor(private _dataService: NoteService) {
    }

    ngOnInit() {
        this._dataService
            .getAll()
            .subscribe((data: NoteItem[]) => this.myItems = data)
            .catch(handleException)                                     
            () => console.log("getAllItems() complete from init"));
    }
}

function handleException(error: any) {
  // log error
  let errorMsg = error.message || `Problem accessing the data!`
  console.error(errorMsg);

  // throw an application level error
  return Observable.throw(errorMsg);

让我们添加一个内部 REST 服务,使用 ASP.NET Core WebAPI 控制器

在访问另一个 ASP.NET Core 项目之前,我们可以通过在我们的 ASP.NET 项目中添加一个新控制器来轻松模拟。这有助于我们使用单个解决方案更轻松地运行和测试。

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace NotebookAppWeb.Controllers
{
    [Produces("application/json")]
    [Route("api/[controller]")]
    public class NotesController : Controller
    {
        private class NoteItem
        {
            public string Id;
            public string Body;
            public string UpdatedOn;
            public string CreatedOn;
            public int UserId;
        }

        // GET: api/values
        [HttpGet]
        public string Get()
        {
            NoteItem[] arrayOfNotes = new NoteItem[] 
            { new NoteItem() { Id = "1", 
            Body = "Hello note !", 
            UpdatedOn = "2016-11-16 10:50:23", 
            CreatedOn = "2016-11-16 10:50:23", UserId = 1 },
            new NoteItem() { Id = "2", 
            Body = "Hello 2 should come after", 
            UpdatedOn = "2016-11-16 10:50:23", 
            CreatedOn = "2016-11-16 10:50:23", UserId = 2 },
            new NoteItem() { Id = "3", 
            Body = "Hello 3 should come latest", 
            UpdatedOn = "2016-11-17 10:50:23", 
            CreatedOn = "2016-11-17 10:50:23", UserId = 3 }};
            return JsonConvert.SerializeObject(arrayOfNotes);
        }
    }

整合

我们现在可以创建一个应用程序,该应用程序连接上述所有概念并模拟一个基本的笔记本应用程序。此应用程序连接到本地控制器作为 REST 服务(Web API 控制器),然后显示接收到的笔记。

连接到 ASP.NET Core WebAPI 和 MongoDB 项目

连接到 ASP.NET Core WebAPI 项目。打开 Github 页面 – https://github.com/fpetru/WebApiMongoDB,在项目说明中,您可以找到如何运行该项目。

一旦设置完成,更改配置以指向此 REST 服务(而不是使用本地控制器)。运行项目。

下一步

这将在下一部分继续,介绍笔记的所有操作。然后,我们将能够添加、编辑或删除笔记。

© . All rights reserved.