本篇將介紹 Angular 4 跟 ASP.NET Core Web API 透過 AJAX 的互動,範例是做一個簡單的通訊錄。功能包含新增(Create)、查詢(Read)、修改(Update)跟刪除(Delete),簡稱CRUD。
程式碼延續前兩篇的範例:ASP.NET Core + Angular 4 教學 - 從無到有 ASP.NET Core + Angular 4 教學 - Webpack打包
1. 安裝 NuGet 套件 過往 ASP.NET MVC 是把 MVC 及 Web API 的套件分開,但在 ASP.NET Core 中 MVC 及 Web API 用的套件是相同的,在 NuGet 管理可以找到 Microsoft.AspNetCore.Mvc 並安裝。
2. 建立 Web API 2.1 註冊 Mvc 服務 Startup.cs AddJsonOptions 的 SerializerSettings 可以參考 ASP.NET Core - Web API JSON 序列化設定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.DependencyInjection;using Newtonsoft.Json.Serialization;namespace MyWebsite { public class Startup { public void ConfigureServices (IServiceCollection services ) { services.AddMvc() .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver() ); } public void Configure (IApplicationBuilder app ) { app.UseDefaultFiles(); app.UseStaticFiles(); app.UseMvc(); } } }
2.2 Models 我習慣用一個 Result Model 來包裝每個 Service 的回傳內容,不論調用 Web API 成功失敗都用此物件包裝,避免直接 throw exception 到 client,產生 http status 200 以外的狀態。
Models\ResultModel.cs
1 2 3 4 5 6 7 8 9 10 11 namespace MyWebsite.Models { public class ResultModel { public bool IsSuccess { get ; set ; } public string Message { get ; set ; } public object Data { get ; set ; } } }
Models\ContactModel.cs ContactModel是接下來範例主要用到的物件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 namespace MyWebsite.Models { public class ContactModel { public int Id { get ; set ; } public string FirstName { get ; set ; } public string LastName { get ; set ; } public string Email { get ; set ; } public string PhoneNumber { get ; set ; } public string Address { get ; set ; } } }
2.3 Controllers 建立一支符合 RESTful 的 CRUD Controller Controllers\ContactController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 using Microsoft.AspNetCore.Mvc;using MyWebsite.Models;using System.Collections.Generic;using System.Linq;namespace MyWebsite.Controllers { [Route("api/[controller]" ) ] public class ContactController : Controller { private static List<ContactModel> _contacts = new List<ContactModel>(); [HttpGet("{id}" ) ] public ResultModel Get (int id ) { var result = new ResultModel(); result.Data = _contacts.SingleOrDefault(c => c.Id == id); result.IsSuccess = result.Data != null ; return result; } [HttpPost ] public ResultModel Post ([FromBody]ContactModel contact ) { var result = new ResultModel(); contact.Id = _contacts.Count() == 0 ? 1 : _contacts.Max(c => c.Id) + 1 ; _contacts.Add(contact); result.Data = contact.Id; result.IsSuccess = true ; return result; } [HttpPut ] public ResultModel Put ([FromBody]ContactModel contact ) { var result = new ResultModel(); int index; if ((index = _contacts.FindIndex(c => c.Id == contact.Id)) != -1 ) { _contacts[index] = contact; result.IsSuccess = true ; } return result; } [HttpDelete("{id}" ) ] public ResultModel Delete (int id ) { var result = new ResultModel(); int index; if ((index = _contacts.FindIndex(c => c.Id == id)) != -1 ) { _contacts.RemoveAt(index); result.IsSuccess = true ; } return result; } } }
2.4 執行結果 直接用瀏覽器打開 /api/contact/1,就可以看到回傳畫面如下:
如果有安裝 Postman 或類似工具的話可以測測看其他的 methods:
3. 建立 Angular 4 3.1 NgModule 這個範例會用到兩個模組:
Web API 用到的 AJAX 需要 HttpModule。 Form 的 ngModel 互動需要 FormsModule。 wwwroot\app\main.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { NgModule } from "@angular/core" ;import { BrowserModule } from "@angular/platform-browser" ;import { platformBrowserDynamic } from "@angular/platform-browser-dynamic" ;import { HttpModule } from "@angular/http" ;import { FormsModule } from "@angular/forms" ;import { AppComponent } from "./app.component" ;@NgModule ({ imports : [ BrowserModule , HttpModule , FormsModule ], declarations : [AppComponent ], bootstrap : [AppComponent ] }) export class AppModule { }platformBrowserDynamic ().bootstrapModule (AppModule );
3.2 Component wwwroot\app\app.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 import { Component } from "@angular/core" ;import { Http } from "@angular/http" ;import * as models from "./models" @Component ({ selector : "my-app" , template : require ("./app.component.html" ) }) export class AppComponent { private api : string = "/api/contact" ; model : models.ContactModel ; contactId : number; message : string; constructor (private http: Http ) { this .clear (); } find (): void { this .clearMessage (); if (Number (this .contactId ) > 0 ) { this .http .get (`${this .api} /${this .contactId} ` ).subscribe ( (response ) => { let result : models.ResultModel = response.json (); if (!result.IsSuccess ) { this .showMessage (`Id: ${this .contactId} not found` ); this .clear (); } else { this .model = result.Data ; } }); } else { this .showMessage ("Contact Id incorrect!" ); this .clear (); } } add (): void { this .clearMessage (); this .http .post (this .api , this .model ).subscribe ( (response ) => { let result : models.ResultModel = response.json (); if (!result.IsSuccess ) { this .showMessage (result.Message ); } else { this .showMessage (`Added successfully, Id: ${result.Data} ` ); this .clear (); } }); } save (): void { this .clearMessage (); this .http .put (this .api , this .model ).subscribe ( (response ) => { let result : models.ResultModel = response.json (); if (!result.IsSuccess ) { this .showMessage (result.Message ); } else { this .showMessage (`Saved successfully, Id: ${this .model.Id} ` ); this .clear (); } }); } delete (): void { this .clearMessage (); this .http .delete (`${this .api} /${this .contactId} ` ).subscribe ( (response ) => { let result : models.ResultModel = response.json (); if (!result.IsSuccess ) { this .showMessage (`Id: ${this .contactId} not found` ); } else { this .showMessage (`Delete successfully, Id: ${this .contactId} ` ); this .clear (); } }); } clear (): void { this .contactId = null ; this .model = new models.ContactModel (); } clearMessage (): void { this .message = "" ; } showMessage (message : string): void { this .message = message; } }
3.3 Models 新增 wwwroot\app\models.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export class ResultModel { public IsSuccess : boolean; public Message : string; public Data : any; } export class ContactModel { public Id : number; public FirstName : string; public LastName : string; public PhoneNumber : string; public Email : string; public Address : string; }
3.4 Views wwwroot\app\app.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <h2 > Contact Card</h2 > <div > <label > Find by Id</label > <input type ="text" name ="contactId" [(ngModel )]="contactId" /> <input type ="button" (click )="find()" value ="Find" /> </div > <br /> <div > {{message}}</div > <br /> <form > <input type ="hidden" name ="Id" [(ngModel )]="model.Id" /> <div > <label > First Name</label > <div > <input type ="text" name ="FirstName" [(ngModel )]="model.FirstName" /> </div > </div > <div > <label > Last Name</label > <div > <input type ="text" name ="LastName" [(ngModel )]="model.LastName" /> </div > </div > <div > <label > Phone Number</label > <div > <input type ="text" name ="PhoneNumber" [(ngModel )]="model.PhoneNumber" /> </div > </div > <div > <label > Email</label > <div > <input type ="text" name ="Email" [(ngModel )]="model.Email" /> </div > </div > <div > <label > Address</label > <div > <input type ="text" name ="Address" [(ngModel )]="model.Address" /> </div > </div > <div > <input *ngIf ="!model.Id" type ="button" (click )="add()" value ="Add" /> <input *ngIf ="model.Id" type ="button" (click )="save()" value ="Save" /> <input *ngIf ="model.Id" type ="button" (click )="delete()" value ="Delete" /> <input type ="button" (click )="clear()" value ="Clear" /> </div > </form >
3.5 執行結果
程式碼下載 asp-net-core-angular-web-api-crud